summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--StubLibraries.bp15
-rw-r--r--api/current.txt6
-rwxr-xr-xapi/system-current.txt21
-rw-r--r--api/test-current.txt3
-rw-r--r--core/java/android/app/role/RoleManager.java3
-rw-r--r--core/java/android/app/timedetector/ITimeDetectorService.aidl2
-rw-r--r--core/java/android/app/timedetector/NetworkTimeSuggestion.aidl19
-rw-r--r--core/java/android/app/timedetector/NetworkTimeSuggestion.java129
-rw-r--r--core/java/android/app/timedetector/TimeDetector.java19
-rw-r--r--core/java/android/app/timezonedetector/TimeZoneDetector.java4
-rw-r--r--core/java/android/bluetooth/BluetoothPbap.java39
-rw-r--r--core/java/android/net/LinkProperties.java53
-rw-r--r--core/java/android/net/NetworkUtils.java7
-rw-r--r--core/java/android/net/OWNERS2
-rw-r--r--core/java/android/net/http/OWNERS3
-rw-r--r--core/java/android/provider/CalendarContract.java8
-rw-r--r--core/java/android/provider/Telephony.java10
-rw-r--r--core/java/android/text/format/TimeFormatter.java69
-rw-r--r--core/java/android/text/format/TimeMigrationUtils.java40
-rw-r--r--core/java/android/util/NtpTrustedTime.java17
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java31
-rw-r--r--core/jni/android_net_NetUtils.cpp95
-rw-r--r--core/jni/fd_utils.cpp2
-rw-r--r--core/res/AndroidManifest.xml26
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java66
-rw-r--r--core/tests/coretests/src/android/text/format/TimeMigrationUtilsTest.java120
-rw-r--r--core/xsd/permission.xsd8
-rw-r--r--data/etc/com.android.settings.xml2
-rw-r--r--data/etc/privapp-permissions-platform.xml2
-rw-r--r--media/java/android/media/tv/DvbDeviceInfo.java7
-rw-r--r--media/java/android/media/tv/TvInputManager.java28
-rw-r--r--media/jni/android_media_MediaCodec.cpp10
-rw-r--r--mms/java/android/telephony/MmsManager.java18
-rw-r--r--mms/java/com/android/internal/telephony/IMms.aidl7
-rw-r--r--packages/Tethering/Android.bp6
-rw-r--r--packages/Tethering/jni/android_net_util_TetheringUtils.cpp (renamed from packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp)108
-rw-r--r--packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java3
-rw-r--r--packages/Tethering/src/android/net/util/TetheringUtils.java42
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java7
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java3
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java1
-rw-r--r--packages/Tethering/tests/unit/Android.bp6
-rw-r--r--services/Android.bp6
-rw-r--r--services/api/current.txt1
-rw-r--r--services/api/removed.txt1
-rw-r--r--services/core/java/com/android/server/DropBoxManagerService.java6
-rw-r--r--services/core/java/com/android/server/MmsServiceBroker.java11
-rw-r--r--services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java139
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java8
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java10
-rw-r--r--services/core/java/com/android/server/job/controllers/JobStatus.java10
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java6
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorService.java23
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java4
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java164
-rwxr-xr-xservices/core/java/com/android/server/tv/TvInputManagerService.java10
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java70
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java86
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java315
-rw-r--r--telecomm/java/android/telecom/Connection.java115
-rw-r--r--telephony/common/com/android/internal/telephony/SmsApplication.java44
-rwxr-xr-xtelephony/common/com/google/android/mms/pdu/PduPersister.java5
-rw-r--r--telephony/java/android/telephony/SignalStrength.java17
-rw-r--r--telephony/java/android/telephony/SmsManager.java31
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java2
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java93
-rw-r--r--telephony/java/android/telephony/data/ApnSetting.java5
-rw-r--r--telephony/java/com/android/ims/ImsConfig.java3
-rw-r--r--telephony/java/com/android/internal/telephony/ISms.aidl37
-rw-r--r--telephony/java/com/android/internal/telephony/ISmsImplBase.java5
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyIntents.java18
-rw-r--r--telephony/java/com/android/internal/telephony/util/HandlerExecutor.java47
-rw-r--r--tests/TelephonyCommonTests/Android.bp48
-rw-r--r--tests/TelephonyCommonTests/AndroidManifest.xml30
-rw-r--r--tests/TelephonyCommonTests/AndroidTest.xml30
-rw-r--r--tests/TelephonyCommonTests/jarjar-rules.txt1
-rw-r--r--tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java238
-rw-r--r--tests/net/TEST_MAPPING7
-rw-r--r--tests/net/common/java/android/net/LinkPropertiesTest.java17
-rw-r--r--tests/net/integration/Android.bp1
84 files changed, 2125 insertions, 613 deletions
diff --git a/Android.bp b/Android.bp
index 808879f8839a..0612a5335390 100644
--- a/Android.bp
+++ b/Android.bp
@@ -603,6 +603,7 @@ filegroup {
"core/java/com/android/internal/util/StateMachine.java",
"core/java/com/android/internal/util/TrafficStatsConstants.java",
"core/java/com/android/internal/util/WakeupMessage.java",
+ "core/java/com/android/internal/util/TokenBucket.java",
"core/java/android/net/shared/*.java",
],
}
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 78f1b9ca26e5..d1950474da5a 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -217,21 +217,6 @@ java_library_static {
defaults: ["framework-stubs-default"],
}
-java_system_modules {
- name: "android_stubs_current_system_modules",
- libs: ["android_stubs_current"],
-}
-
-java_system_modules {
- name: "android_system_stubs_current_system_modules",
- libs: ["android_system_stubs_current"],
-}
-
-java_system_modules {
- name: "android_test_stubs_current_system_modules",
- libs: ["android_test_stubs_current"],
-}
-
/////////////////////////////////////////////////////////////////////
// hwbinder.stubs provides APIs required for building HIDL Java
// libraries.
diff --git a/api/current.txt b/api/current.txt
index 6d5d228d295e..a58c4f09efeb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28888,6 +28888,7 @@ package android.net {
method public boolean addRoute(@NonNull android.net.RouteInfo);
method public void clear();
method public int describeContents();
+ method @Nullable public java.net.Inet4Address getDhcpServerAddress();
method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
method @Nullable public String getDomains();
method @Nullable public android.net.ProxyInfo getHttpProxy();
@@ -28899,6 +28900,7 @@ package android.net {
method @NonNull public java.util.List<android.net.RouteInfo> getRoutes();
method public boolean isPrivateDnsActive();
method public boolean isWakeOnLanSupported();
+ method public void setDhcpServerAddress(@Nullable java.net.Inet4Address);
method public void setDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
method public void setDomains(@Nullable String);
method public void setHttpProxy(@Nullable android.net.ProxyInfo);
@@ -42575,6 +42577,7 @@ package android.system {
method public static void execve(String, String[], String[]) throws android.system.ErrnoException;
method public static void fchmod(java.io.FileDescriptor, int) throws android.system.ErrnoException;
method public static void fchown(java.io.FileDescriptor, int, int) throws android.system.ErrnoException;
+ method public static int fcntlInt(@NonNull java.io.FileDescriptor, int, int) throws android.system.ErrnoException;
method public static void fdatasync(java.io.FileDescriptor) throws android.system.ErrnoException;
method public static android.system.StructStat fstat(java.io.FileDescriptor) throws android.system.ErrnoException;
method public static android.system.StructStatVfs fstatvfs(java.io.FileDescriptor) throws android.system.ErrnoException;
@@ -45087,6 +45090,7 @@ package android.telephony {
method public int getLevel();
method @Deprecated public boolean isGsm();
method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SignalStrength> CREATOR;
field public static final int INVALID = 2147483647; // 0x7fffffff
}
@@ -45095,7 +45099,7 @@ package android.telephony {
method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
method public java.util.ArrayList<java.lang.String> divideMessage(String);
method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
- method public android.os.Bundle getCarrierConfigValues();
+ method @Nullable public android.os.Bundle getCarrierConfigValues();
method public static android.telephony.SmsManager getDefault();
method public static int getDefaultSmsSubscriptionId();
method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 0edf9ab40821..e62360ef393b 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1162,6 +1162,7 @@ package android.app.role {
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean addRoleHolderFromController(@NonNull String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method @Nullable public String getDefaultSmsPackage(int);
method @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
@@ -1428,6 +1429,7 @@ package android.bluetooth {
public class BluetoothPbap implements android.bluetooth.BluetoothProfile {
method public int getConnectionState(@Nullable android.bluetooth.BluetoothDevice);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";
}
@@ -3972,6 +3974,15 @@ package android.media.soundtrigger {
package android.media.tv {
+ public final class DvbDeviceInfo implements android.os.Parcelable {
+ ctor public DvbDeviceInfo(int, int);
+ method public int describeContents();
+ method public int getAdapterId();
+ method public int getDeviceId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.DvbDeviceInfo> CREATOR;
+ }
+
public final class TvContentRatingSystemInfo implements android.os.Parcelable {
method public static android.media.tv.TvContentRatingSystemInfo createTvContentRatingSystemInfo(int, android.content.pm.ApplicationInfo);
method public int describeContents();
@@ -4086,12 +4097,14 @@ package android.media.tv {
method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void addBlockedRating(@NonNull android.media.tv.TvContentRating);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean captureFrame(String, android.view.Surface, android.media.tv.TvStreamConfig);
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public java.util.List<android.media.tv.TvStreamConfig> getAvailableTvStreamConfigList(String);
+ method @NonNull @RequiresPermission("android.permission.DVB_DEVICE") public java.util.List<android.media.tv.DvbDeviceInfo> getDvbDeviceList();
method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public java.util.List<android.media.tv.TvInputHardwareInfo> getHardwareList();
method @RequiresPermission(android.Manifest.permission.READ_CONTENT_RATING_SYSTEMS) public java.util.List<android.media.tv.TvContentRatingSystemInfo> getTvContentRatingSystemList();
method @RequiresPermission(android.Manifest.permission.CAPTURE_TV_INPUT) public boolean isSingleSessionActive();
method @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS) public void notifyPreviewProgramAddedToWatchNext(String, long, long);
method @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS) public void notifyPreviewProgramBrowsableDisabled(String, long);
method @RequiresPermission(android.Manifest.permission.NOTIFY_TV_INPUTS) public void notifyWatchNextProgramBrowsableDisabled(String, long);
+ method @Nullable @RequiresPermission("android.permission.DVB_DEVICE") public android.os.ParcelFileDescriptor openDvbDevice(@NonNull android.media.tv.DvbDeviceInfo, int);
method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public void releaseTvInputHardware(int, android.media.tv.TvInputManager.Hardware);
method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void removeBlockedRating(@NonNull android.media.tv.TvContentRating);
method @RequiresPermission(android.Manifest.permission.MODIFY_PARENTAL_CONTROLS) public void setParentalControlsEnabled(boolean);
@@ -6735,7 +6748,9 @@ package android.provider {
public static final class Telephony.Carriers implements android.provider.BaseColumns {
field public static final String APN_SET_ID = "apn_set_id";
field public static final int CARRIER_EDITED = 4; // 0x4
+ field @NonNull public static final android.net.Uri DPC_URI;
field public static final String EDITED_STATUS = "edited";
+ field public static final int INVALID_APN_ID = -1; // 0xffffffff
field public static final String MAX_CONNECTIONS = "max_conns";
field public static final String MODEM_PERSIST = "modem_cognitive";
field public static final String MTU = "mtu";
@@ -8931,6 +8946,7 @@ package android.telephony {
}
public class TelephonyManager {
+ method public int addDevicePolicyOverrideApn(@NonNull android.content.Context, @NonNull android.telephony.data.ApnSetting);
method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String);
method public int checkCarrierPrivilegesForPackage(String);
method public int checkCarrierPrivilegesForPackageAnyPhone(String);
@@ -8957,6 +8973,7 @@ package android.telephony {
method @Deprecated public boolean getDataEnabled();
method @Deprecated public boolean getDataEnabled(int);
method @Nullable public static android.content.ComponentName getDefaultRespondViaMessageApplication(@NonNull android.content.Context, boolean);
+ method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context);
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceSoftwareVersion(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
method public int getEmergencyNumberDbVersion();
@@ -8991,15 +9008,17 @@ package android.telephony {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isInEmergencySmsMode();
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isManualNetworkSelectionAllowed();
method public boolean isModemEnabledForSlot(int);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isOpportunisticNetworkEnabled();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTetheringApnRequired();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isTetheringApnRequired();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled();
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
+ method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting);
method public boolean needsOtaServiceProvisioning();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio();
diff --git a/api/test-current.txt b/api/test-current.txt
index 22ac3abcefd9..80f7e4bff61c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3040,14 +3040,17 @@ package android.telephony {
}
public class TelephonyManager {
+ method public int addDevicePolicyOverrideApn(@NonNull android.content.Context, @NonNull android.telephony.data.ApnSetting);
method public int checkCarrierPrivilegesForPackage(String);
method public int getCarrierIdListVersion();
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
method @Nullable public static android.content.ComponentName getDefaultRespondViaMessageApplication(@NonNull android.content.Context, boolean);
+ method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context);
method public int getEmergencyNumberDbVersion();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag();
method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getNetworkCountryIso(int);
method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion();
+ method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String);
method public void setCarrierTestOverride(String, String, String, String, String, String, String, String, String);
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index bb04a2e52712..b9cda6c7c183 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -629,9 +629,12 @@ public final class RoleManager {
* {@link Manifest.permission#OBSERVE_ROLE_HOLDERS}, as required by
* {@link android.provider.Telephony.Sms#getDefaultSmsPackage(Context)}
*
+ * @param userId The user ID to get the default SMS package for.
+ * @return the package name of the default SMS app, or {@code null} if not configured.
* @hide
*/
@Nullable
+ @SystemApi
public String getDefaultSmsPackage(@UserIdInt int userId) {
try {
return mService.getDefaultSmsPackage(userId);
diff --git a/core/java/android/app/timedetector/ITimeDetectorService.aidl b/core/java/android/app/timedetector/ITimeDetectorService.aidl
index 9877fc741b7b..de8f4700de2d 100644
--- a/core/java/android/app/timedetector/ITimeDetectorService.aidl
+++ b/core/java/android/app/timedetector/ITimeDetectorService.aidl
@@ -17,6 +17,7 @@
package android.app.timedetector;
import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
/**
@@ -35,4 +36,5 @@ import android.app.timedetector.PhoneTimeSuggestion;
interface ITimeDetectorService {
void suggestPhoneTime(in PhoneTimeSuggestion timeSuggestion);
void suggestManualTime(in ManualTimeSuggestion timeSuggestion);
+ void suggestNetworkTime(in NetworkTimeSuggestion timeSuggestion);
}
diff --git a/core/java/android/app/timedetector/NetworkTimeSuggestion.aidl b/core/java/android/app/timedetector/NetworkTimeSuggestion.aidl
new file mode 100644
index 000000000000..731c907f6837
--- /dev/null
+++ b/core/java/android/app/timedetector/NetworkTimeSuggestion.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.app.timedetector;
+
+parcelable NetworkTimeSuggestion;
diff --git a/core/java/android/app/timedetector/NetworkTimeSuggestion.java b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
new file mode 100644
index 000000000000..4c55ba12d881
--- /dev/null
+++ b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
@@ -0,0 +1,129 @@
+/*
+ * 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.app.timedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.TimestampedValue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A time signal from a network time source like NTP. The value consists of the number of
+ * milliseconds elapsed since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime
+ * clock when that number was established. The elapsed realtime clock is considered accurate but
+ * volatile, so time signals must not be persisted across device resets.
+ *
+ * @hide
+ */
+public final class NetworkTimeSuggestion implements Parcelable {
+
+ public static final @NonNull Creator<NetworkTimeSuggestion> CREATOR =
+ new Creator<NetworkTimeSuggestion>() {
+ public NetworkTimeSuggestion createFromParcel(Parcel in) {
+ return NetworkTimeSuggestion.createFromParcel(in);
+ }
+
+ public NetworkTimeSuggestion[] newArray(int size) {
+ return new NetworkTimeSuggestion[size];
+ }
+ };
+
+ @NonNull
+ private final TimestampedValue<Long> mUtcTime;
+ @Nullable
+ private ArrayList<String> mDebugInfo;
+
+ public NetworkTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) {
+ mUtcTime = Objects.requireNonNull(utcTime);
+ Objects.requireNonNull(utcTime.getValue());
+ }
+
+ private static NetworkTimeSuggestion createFromParcel(Parcel in) {
+ TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
+ NetworkTimeSuggestion suggestion = new NetworkTimeSuggestion(utcTime);
+ @SuppressWarnings("unchecked")
+ ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
+ suggestion.mDebugInfo = debugInfo;
+ return suggestion;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mUtcTime, 0);
+ dest.writeList(mDebugInfo);
+ }
+
+ @NonNull
+ public TimestampedValue<Long> getUtcTime() {
+ return mUtcTime;
+ }
+
+ @NonNull
+ public List<String> getDebugInfo() {
+ return mDebugInfo == null
+ ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
+ }
+
+ /**
+ * Associates information with the instance that can be useful for debugging / logging. The
+ * information is present in {@link #toString()} but is not considered for
+ * {@link #equals(Object)} and {@link #hashCode()}.
+ */
+ public void addDebugInfo(String... debugInfos) {
+ if (mDebugInfo == null) {
+ mDebugInfo = new ArrayList<>();
+ }
+ mDebugInfo.addAll(Arrays.asList(debugInfos));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ NetworkTimeSuggestion that = (NetworkTimeSuggestion) o;
+ return Objects.equals(mUtcTime, that.mUtcTime);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUtcTime);
+ }
+
+ @Override
+ public String toString() {
+ return "NetworkTimeSuggestion{"
+ + "mUtcTime=" + mUtcTime
+ + ", mDebugInfo=" + mDebugInfo
+ + '}';
+ }
+}
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index 48d5cd2d65a5..af9ece00f491 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -48,7 +48,7 @@ public class TimeDetector {
* signal if better signals are available such as those that come from more reliable sources or
* were determined more recently.
*/
- @RequiresPermission(android.Manifest.permission.SET_TIME)
+ @RequiresPermission(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE)
public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
if (DEBUG) {
Log.d(TAG, "suggestPhoneTime called: " + timeSuggestion);
@@ -63,7 +63,7 @@ public class TimeDetector {
/**
* Suggests the user's manually entered current time to the detector.
*/
- @RequiresPermission(android.Manifest.permission.SET_TIME)
+ @RequiresPermission(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE)
public void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion) {
if (DEBUG) {
Log.d(TAG, "suggestManualTime called: " + timeSuggestion);
@@ -85,4 +85,19 @@ public class TimeDetector {
manualTimeSuggestion.addDebugInfo(why);
return manualTimeSuggestion;
}
+
+ /**
+ * Suggests the time according to a network time source like NTP.
+ */
+ @RequiresPermission(android.Manifest.permission.SET_TIME)
+ public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) {
+ if (DEBUG) {
+ Log.d(TAG, "suggestNetworkTime called: " + timeSuggestion);
+ }
+ try {
+ mITimeDetectorService.suggestNetworkTime(timeSuggestion);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
index 387a36bba608..e165d8a76caa 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetector.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -47,7 +47,7 @@ public class TimeZoneDetector {
* detector may ignore the signal based on system settings, whether better information is
* available, and so on.
*/
- @RequiresPermission(android.Manifest.permission.SET_TIME_ZONE)
+ @RequiresPermission(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE)
public void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion) {
if (DEBUG) {
Log.d(TAG, "suggestPhoneTimeZone called: " + timeZoneSuggestion);
@@ -63,7 +63,7 @@ public class TimeZoneDetector {
* Suggests the current time zone, determined for the user's manually information, to the
* detector. The detector may ignore the signal based on system settings.
*/
- @RequiresPermission(android.Manifest.permission.SET_TIME_ZONE)
+ @RequiresPermission(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE)
public void suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) {
if (DEBUG) {
Log.d(TAG, "suggestManualTimeZone called: " + timeZoneSuggestion);
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index df0289643ee0..291015070385 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -16,7 +16,10 @@
package android.bluetooth;
+import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
@@ -271,6 +274,42 @@ public class BluetoothPbap implements BluetoothProfile {
}
/**
+ * Pbap does not store connection policy, so this function only disconnects Pbap if
+ * connectionPolicy is CONNECTION_POLICY_FORBIDDEN.
+ *
+ * <p> The device should already be paired.
+ * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
+ * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
+ *
+ * @param device Paired bluetooth device
+ * @param connectionPolicy is the connection policy to set to for this profile
+ * @return true if pbap is successfully disconnected, false otherwise
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
+ @ConnectionPolicy int connectionPolicy) {
+ if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
+ try {
+ final IBluetoothPbap service = mService;
+ if (service != null && isEnabled()
+ && isValidDevice(device)) {
+ if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
+ && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
+ return false;
+ }
+ return service.setConnectionPolicy(device, connectionPolicy);
+ }
+ if (service == null) Log.w(TAG, "Proxy not attached to service");
+ return false;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+ return false;
+ }
+ }
+
+ /**
* Disconnects the current Pbap client (PCE). Currently this call blocks,
* it may soon be made asynchronous. Returns false if this proxy object is
* not currently connected to the Pbap service.
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index ed509cb3da34..89ec3e776d41 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -63,6 +63,7 @@ public final class LinkProperties implements Parcelable {
private String mPrivateDnsServerName;
private String mDomains;
private ArrayList<RouteInfo> mRoutes = new ArrayList<>();
+ private Inet4Address mDhcpServerAddress;
private ProxyInfo mHttpProxy;
private int mMtu;
// in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
@@ -196,6 +197,7 @@ public final class LinkProperties implements Parcelable {
addStackedLink(l);
}
setMtu(source.mMtu);
+ setDhcpServerAddress(source.getDhcpServerAddress());
mTcpBufferSizes = source.mTcpBufferSizes;
mNat64Prefix = source.mNat64Prefix;
mWakeOnLanSupported = source.mWakeOnLanSupported;
@@ -460,6 +462,24 @@ public final class LinkProperties implements Parcelable {
}
/**
+ * Set DHCP server address.
+ *
+ * @param serverAddress the server address to set.
+ */
+ public void setDhcpServerAddress(@Nullable Inet4Address serverAddress) {
+ mDhcpServerAddress = serverAddress;
+ }
+
+ /**
+ * Get DHCP server address
+ *
+ * @return The current DHCP server address.
+ */
+ public @Nullable Inet4Address getDhcpServerAddress() {
+ return mDhcpServerAddress;
+ }
+
+ /**
* Returns the private DNS server name that is in use. If not {@code null},
* private DNS is in strict mode. In this mode, applications should ensure
* that all DNS queries are encrypted and sent to this hostname and that
@@ -851,6 +871,7 @@ public final class LinkProperties implements Parcelable {
mHttpProxy = null;
mStackedLinks.clear();
mMtu = 0;
+ mDhcpServerAddress = null;
mTcpBufferSizes = null;
mNat64Prefix = null;
mWakeOnLanSupported = false;
@@ -919,6 +940,11 @@ public final class LinkProperties implements Parcelable {
resultJoiner.add("WakeOnLanSupported: true");
}
+ if (mDhcpServerAddress != null) {
+ resultJoiner.add("ServerAddress:");
+ resultJoiner.add(mDhcpServerAddress.toString());
+ }
+
if (mTcpBufferSizes != null) {
resultJoiner.add("TcpBufferSizes:");
resultJoiner.add(mTcpBufferSizes);
@@ -1273,6 +1299,17 @@ public final class LinkProperties implements Parcelable {
}
/**
+ * Compares this {@code LinkProperties} DHCP server address against the target
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ * @hide
+ */
+ public boolean isIdenticalDhcpServerAddress(@NonNull LinkProperties target) {
+ return Objects.equals(mDhcpServerAddress, target.mDhcpServerAddress);
+ }
+
+ /**
* Compares this {@code LinkProperties} interface addresses against the target
*
* @param target LinkProperties to compare.
@@ -1489,6 +1526,7 @@ public final class LinkProperties implements Parcelable {
*/
return isIdenticalInterfaceName(target)
&& isIdenticalAddresses(target)
+ && isIdenticalDhcpServerAddress(target)
&& isIdenticalDnses(target)
&& isIdenticalPrivateDns(target)
&& isIdenticalValidatedPrivateDnses(target)
@@ -1613,6 +1651,7 @@ public final class LinkProperties implements Parcelable {
+ mMtu * 51
+ ((null == mTcpBufferSizes) ? 0 : mTcpBufferSizes.hashCode())
+ (mUsePrivateDns ? 57 : 0)
+ + ((null == mDhcpServerAddress) ? 0 : mDhcpServerAddress.hashCode())
+ mPcscfs.size() * 67
+ ((null == mPrivateDnsServerName) ? 0 : mPrivateDnsServerName.hashCode())
+ Objects.hash(mNat64Prefix)
@@ -1635,6 +1674,7 @@ public final class LinkProperties implements Parcelable {
dest.writeString(mPrivateDnsServerName);
writeAddresses(dest, mPcscfs);
dest.writeString(mDomains);
+ writeAddress(dest, mDhcpServerAddress);
dest.writeInt(mMtu);
dest.writeString(mTcpBufferSizes);
dest.writeInt(mRoutes.size());
@@ -1663,8 +1703,9 @@ public final class LinkProperties implements Parcelable {
}
}
- private static void writeAddress(@NonNull Parcel dest, @NonNull InetAddress addr) {
- dest.writeByteArray(addr.getAddress());
+ private static void writeAddress(@NonNull Parcel dest, @Nullable InetAddress addr) {
+ byte[] addressBytes = (addr == null ? null : addr.getAddress());
+ dest.writeByteArray(addressBytes);
if (addr instanceof Inet6Address) {
final Inet6Address v6Addr = (Inet6Address) addr;
final boolean hasScopeId = v6Addr.getScopeId() != 0;
@@ -1673,9 +1714,11 @@ public final class LinkProperties implements Parcelable {
}
}
- @NonNull
+ @Nullable
private static InetAddress readAddress(@NonNull Parcel p) throws UnknownHostException {
final byte[] addr = p.createByteArray();
+ if (addr == null) return null;
+
if (addr.length == INET6_ADDR_LENGTH) {
final boolean hasScopeId = p.readBoolean();
final int scopeId = hasScopeId ? p.readInt() : 0;
@@ -1722,6 +1765,10 @@ public final class LinkProperties implements Parcelable {
} catch (UnknownHostException e) { }
}
netProp.setDomains(in.readString());
+ try {
+ netProp.setDhcpServerAddress((Inet4Address) InetAddress
+ .getByAddress(in.createByteArray()));
+ } catch (UnknownHostException e) { }
netProp.setMtu(in.readInt());
netProp.setTcpBufferSizes(in.readString());
addressCount = in.readInt();
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index d0f54b4c7f2d..01cb9883564a 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -61,13 +61,6 @@ public class NetworkUtils {
public static native void detachBPFFilter(FileDescriptor fd) throws SocketException;
/**
- * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements.
- * @param fd the socket's {@link FileDescriptor}.
- * @param ifIndex the interface index.
- */
- public native static void setupRaSocket(FileDescriptor fd, int ifIndex) throws SocketException;
-
- /**
* Binds the current process to the network designated by {@code netId}. All sockets created
* in the future (and not explicitly bound via a bound {@link SocketFactory} (see
* {@link Network#getSocketFactory}) will be bound to this network. Note that if this
diff --git a/core/java/android/net/OWNERS b/core/java/android/net/OWNERS
index a1c7fce67d30..767b69351065 100644
--- a/core/java/android/net/OWNERS
+++ b/core/java/android/net/OWNERS
@@ -8,4 +8,4 @@ lorenzo@google.com
reminv@google.com
satk@google.com
-per-file SSL*, Uri*, Url* = flooey@google.com, narayan@google.com, tobiast@google.com
+per-file SSL*, Uri*, Url* = prb@google.com, dauletz@google.com, narayan@google.com, tobiast@google.com
diff --git a/core/java/android/net/http/OWNERS b/core/java/android/net/http/OWNERS
index 6b8c9edf4257..309261277024 100644
--- a/core/java/android/net/http/OWNERS
+++ b/core/java/android/net/http/OWNERS
@@ -1,3 +1,4 @@
-flooey@google.com
narayan@google.com
tobiast@google.com
+include platform/libcore:/OWNERS
+include platform/external/conscrypt:/OWNERS
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index f1d90be9aafe..7285166cdd5f 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -40,7 +40,7 @@ import android.database.DatabaseUtils;
import android.net.Uri;
import android.os.RemoteException;
import android.text.format.DateUtils;
-import android.text.format.Time;
+import android.text.format.TimeMigrationUtils;
import android.util.Log;
import com.android.internal.util.Preconditions;
@@ -1680,7 +1680,7 @@ public final class CalendarContract {
* <h3>Writing to Events</h3> There are further restrictions on all Updates
* and Inserts in the Events table:
* <ul>
- * <li>If allDay is set to 1 eventTimezone must be {@link Time#TIMEZONE_UTC}
+ * <li>If allDay is set to 1 eventTimezone must be "UTC"
* and the time must correspond to a midnight boundary.</li>
* <li>Exceptions are not allowed to recur. If rrule or rdate is not empty,
* original_id and original_sync_id must be empty.</li>
@@ -2609,9 +2609,7 @@ public final class CalendarContract {
@UnsupportedAppUsage
public static void scheduleAlarm(Context context, AlarmManager manager, long alarmTime) {
if (DEBUG) {
- Time time = new Time();
- time.set(alarmTime);
- String schedTime = time.format(" %a, %b %d, %Y %I:%M%P");
+ String schedTime = TimeMigrationUtils.formatMillisWithFixedFormat(alarmTime);
Log.d(TAG, "Schedule alarm at " + alarmTime + " " + schedTime);
}
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index df36f143393b..13d167d5e99a 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3522,7 +3522,8 @@ public final class Telephony {
* can manage DPC-owned APNs.
* @hide
*/
- public static final Uri DPC_URI = Uri.parse("content://telephony/carriers/dpc");
+ @SystemApi
+ public static final @NonNull Uri DPC_URI = Uri.parse("content://telephony/carriers/dpc");
/**
* The {@code content://} style URL to be called from Telephony to query APNs.
@@ -3831,6 +3832,13 @@ public final class Telephony {
public static final String USER_EDITABLE = "user_editable";
/**
+ * Integer value denoting an invalid APN id
+ * @hide
+ */
+ @SystemApi
+ public static final int INVALID_APN_ID = -1;
+
+ /**
* {@link #EDITED_STATUS APN edit status} indicates that this APN has not been edited or
* fails to edit.
* <p>Type: INTEGER </p>
diff --git a/core/java/android/text/format/TimeFormatter.java b/core/java/android/text/format/TimeFormatter.java
index 5a14092c95a8..f7fd89d7d819 100644
--- a/core/java/android/text/format/TimeFormatter.java
+++ b/core/java/android/text/format/TimeFormatter.java
@@ -26,6 +26,9 @@ import libcore.icu.LocaleData;
import libcore.util.ZoneInfo;
import java.nio.CharBuffer;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
import java.util.Formatter;
import java.util.Locale;
import java.util.TimeZone;
@@ -86,6 +89,59 @@ class TimeFormatter {
}
/**
+ * The implementation of {@link TimeMigrationUtils#formatMillisWithFixedFormat(long)} for
+ * 2038-safe formatting with the pattern "%Y-%m-%d %H:%M:%S" and including the historic
+ * incorrect digit localization behavior.
+ */
+ String formatMillisWithFixedFormat(long timeMillis) {
+ // This method is deliberately not a general purpose replacement for
+ // format(String, ZoneInfo.WallTime, ZoneInfo): It hard-codes the pattern used; many of the
+ // pattern characters supported by Time.format() have unusual behavior which would make
+ // using java.time.format or similar packages difficult. It would be a lot of work to share
+ // behavior and many internal Android usecases can be covered by this common pattern
+ // behavior.
+
+ // No need to worry about overflow / underflow: long millis is representable by Instant and
+ // LocalDateTime with room to spare.
+ Instant instant = Instant.ofEpochMilli(timeMillis);
+
+ // Date/times are calculated in the current system default time zone.
+ LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
+
+ // You'd think it would be as simple as:
+ // DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", locale);
+ // return formatter.format(localDateTime);
+ // but we retain Time's behavior around digits.
+
+ StringBuilder stringBuilder = new StringBuilder(19);
+
+ // This effectively uses the US locale because number localization is handled separately
+ // (see below).
+ stringBuilder.append(localDateTime.getYear());
+ stringBuilder.append('-');
+ append2DigitNumber(stringBuilder, localDateTime.getMonthValue());
+ stringBuilder.append('-');
+ append2DigitNumber(stringBuilder, localDateTime.getDayOfMonth());
+ stringBuilder.append(' ');
+ append2DigitNumber(stringBuilder, localDateTime.getHour());
+ stringBuilder.append(':');
+ append2DigitNumber(stringBuilder, localDateTime.getMinute());
+ stringBuilder.append(':');
+ append2DigitNumber(stringBuilder, localDateTime.getSecond());
+
+ String result = stringBuilder.toString();
+ return localizeDigits(result);
+ }
+
+ /** Zero-pads value as needed to achieve a 2-digit number. */
+ private static void append2DigitNumber(StringBuilder builder, int value) {
+ if (value < 10) {
+ builder.append('0');
+ }
+ builder.append(value);
+ }
+
+ /**
* Format the specified {@code wallTime} using {@code pattern}. The output is returned.
*/
public String format(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) {
@@ -99,12 +155,9 @@ class TimeFormatter {
formatInternal(pattern, wallTime, zoneInfo);
String result = stringBuilder.toString();
- // This behavior is the source of a bug since some formats are defined as being
- // in ASCII and not localized.
- if (localeData.zeroDigit != '0') {
- result = localizeDigits(result);
- }
- return result;
+ // The localizeDigits() behavior is the source of a bug since some formats are defined
+ // as being in ASCII and not localized.
+ return localizeDigits(result);
} finally {
outputBuilder = null;
numberFormatter = null;
@@ -112,6 +165,10 @@ class TimeFormatter {
}
private String localizeDigits(String s) {
+ if (localeData.zeroDigit == '0') {
+ return s;
+ }
+
int length = s.length();
int offsetToLocalizedDigits = localeData.zeroDigit - '0';
StringBuilder result = new StringBuilder(length);
diff --git a/core/java/android/text/format/TimeMigrationUtils.java b/core/java/android/text/format/TimeMigrationUtils.java
new file mode 100644
index 000000000000..17bac8d67b26
--- /dev/null
+++ b/core/java/android/text/format/TimeMigrationUtils.java
@@ -0,0 +1,40 @@
+/*
+ * 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.text.format;
+
+/**
+ * Logic to ease migration away from {@link Time} in Android internal code. {@link Time} is
+ * afflicted by the Y2038 issue and deprecated. The methods here are intended to allow minimal
+ * changes to classes that use {@link Time} for common behavior.
+ *
+ * @hide
+ */
+public class TimeMigrationUtils {
+
+ private TimeMigrationUtils() {}
+
+ /**
+ * A Y2038-safe replacement for various users of the {@link Time#format(String)} with the
+ * pattern "%Y-%m-%d %H:%M:%S". Note, this method retains the unusual localization behavior
+ * originally implemented by Time, which can lead to non-latin numbers being produced if the
+ * default locale does not use latin numbers.
+ */
+ public static String formatMillisWithFixedFormat(long timeMillis) {
+ // Delegate to TimeFormatter so that the unusual localization / threading behavior can be
+ // reused.
+ return new TimeFormatter().formatMillisWithFixedFormat(timeMillis);
+ }
+}
diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java
index da566c934ef7..ea294f010791 100644
--- a/core/java/android/util/NtpTrustedTime.java
+++ b/core/java/android/util/NtpTrustedTime.java
@@ -175,4 +175,21 @@ public class NtpTrustedTime implements TrustedTime {
public long getCachedNtpTimeReference() {
return mCachedNtpElapsedRealtime;
}
+
+ /**
+ * Returns the combination of {@link #getCachedNtpTime()} and {@link
+ * #getCachedNtpTimeReference()} as a {@link TimestampedValue}. This method is useful when
+ * passing the time to another component that will adjust for elapsed time.
+ *
+ * @throws IllegalStateException if there is no cached value
+ */
+ public TimestampedValue<Long> getCachedNtpTimeSignal() {
+ if (!mHasCache) {
+ throw new IllegalStateException("Missing authoritative time source");
+ }
+ if (LOGD) Log.d(TAG, "getCachedNtpTimeSignal() cache hit");
+
+ return new TimestampedValue<>(mCachedNtpElapsedRealtime, mCachedNtpTime);
+ }
+
}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index fa823c4bf2f6..f14145b35db7 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -35,6 +35,7 @@ import com.android.internal.logging.AndroidConfig;
import com.android.server.NetworkManagementSocketTagger;
import dalvik.system.RuntimeHooks;
+import dalvik.system.ThreadPrioritySetter;
import dalvik.system.VMRuntime;
import libcore.content.type.MimeMap;
@@ -204,6 +205,7 @@ public class RuntimeInit {
*/
public static void preForkInit() {
if (DEBUG) Slog.d(TAG, "Entered preForkInit.");
+ RuntimeHooks.setThreadPrioritySetter(new RuntimeThreadPrioritySetter());
RuntimeInit.enableDdms();
// TODO(b/142019040#comment13): Decide whether to load the default instance eagerly, i.e.
// MimeMap.setDefault(DefaultMimeMapFactory.create());
@@ -216,6 +218,35 @@ public class RuntimeInit {
MimeMap.setDefaultSupplier(DefaultMimeMapFactory::create);
}
+ private static class RuntimeThreadPrioritySetter implements ThreadPrioritySetter {
+ // Should remain consistent with kNiceValues[] in system/libartpalette/palette_android.cc
+ private static final int[] NICE_VALUES = {
+ Process.THREAD_PRIORITY_LOWEST, // 1 (MIN_PRIORITY)
+ Process.THREAD_PRIORITY_BACKGROUND + 6,
+ Process.THREAD_PRIORITY_BACKGROUND + 3,
+ Process.THREAD_PRIORITY_BACKGROUND,
+ Process.THREAD_PRIORITY_DEFAULT, // 5 (NORM_PRIORITY)
+ Process.THREAD_PRIORITY_DEFAULT - 2,
+ Process.THREAD_PRIORITY_DEFAULT - 4,
+ Process.THREAD_PRIORITY_URGENT_DISPLAY + 3,
+ Process.THREAD_PRIORITY_URGENT_DISPLAY + 2,
+ Process.THREAD_PRIORITY_URGENT_DISPLAY // 10 (MAX_PRIORITY)
+ };
+
+ @Override
+ public void setPriority(int priority) {
+ // Check NICE_VALUES[] length first.
+ if (NICE_VALUES.length != (1 + Thread.MAX_PRIORITY - Thread.MIN_PRIORITY)) {
+ throw new AssertionError("Unexpected NICE_VALUES.length=" + NICE_VALUES.length);
+ }
+ // Priority should be in the range of MIN_PRIORITY (1) to MAX_PRIORITY (10).
+ if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
+ throw new IllegalArgumentException("Priority out of range: " + priority);
+ }
+ Process.setThreadPriority(NICE_VALUES[priority - Thread.MIN_PRIORITY]);
+ }
+ }
+
@UnsupportedAppUsage
protected static final void commonInit() {
if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 08aa1d97fa1c..ba7fe7ff8739 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -24,9 +24,7 @@
#include <linux/tcp.h>
#include <net/if.h>
#include <netinet/ether.h>
-#include <netinet/icmp6.h>
#include <netinet/ip.h>
-#include <netinet/ip6.h>
#include <netinet/udp.h>
#include <android_runtime/AndroidRuntime.h>
@@ -102,98 +100,6 @@ static void android_net_utils_detachBPFFilter(JNIEnv *env, jobject clazz, jobjec
}
}
-static void android_net_utils_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd,
- jint ifIndex)
-{
- static const int kLinkLocalHopLimit = 255;
-
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
-
- // Set an ICMPv6 filter that only passes Router Solicitations.
- struct icmp6_filter rs_only;
- ICMP6_FILTER_SETBLOCKALL(&rs_only);
- ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &rs_only);
- socklen_t len = sizeof(rs_only);
- if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &rs_only, len) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(ICMP6_FILTER): %s", strerror(errno));
- return;
- }
-
- // Most/all of the rest of these options can be set via Java code, but
- // because we're here on account of setting an icmp6_filter go ahead
- // and do it all natively for now.
- //
- // TODO: Consider moving these out to Java.
-
- // Set the multicast hoplimit to 255 (link-local only).
- int hops = kLinkLocalHopLimit;
- len = sizeof(hops);
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, len) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(IPV6_MULTICAST_HOPS): %s", strerror(errno));
- return;
- }
-
- // Set the unicast hoplimit to 255 (link-local only).
- hops = kLinkLocalHopLimit;
- len = sizeof(hops);
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, len) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(IPV6_UNICAST_HOPS): %s", strerror(errno));
- return;
- }
-
- // Explicitly disable multicast loopback.
- int off = 0;
- len = sizeof(off);
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, len) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(IPV6_MULTICAST_LOOP): %s", strerror(errno));
- return;
- }
-
- // Specify the IPv6 interface to use for outbound multicast.
- len = sizeof(ifIndex);
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifIndex, len) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(IPV6_MULTICAST_IF): %s", strerror(errno));
- return;
- }
-
- // Additional options to be considered:
- // - IPV6_TCLASS
- // - IPV6_RECVPKTINFO
- // - IPV6_RECVHOPLIMIT
-
- // Bind to [::].
- const struct sockaddr_in6 sin6 = {
- .sin6_family = AF_INET6,
- .sin6_port = 0,
- .sin6_flowinfo = 0,
- .sin6_addr = IN6ADDR_ANY_INIT,
- .sin6_scope_id = 0,
- };
- auto sa = reinterpret_cast<const struct sockaddr *>(&sin6);
- len = sizeof(sin6);
- if (bind(fd, sa, len) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "bind(IN6ADDR_ANY): %s", strerror(errno));
- return;
- }
-
- // Join the all-routers multicast group, ff02::2%index.
- struct ipv6_mreq all_rtrs = {
- .ipv6mr_multiaddr = {{{0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2}}},
- .ipv6mr_interface = ifIndex,
- };
- len = sizeof(all_rtrs);
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &all_rtrs, len) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(IPV6_JOIN_GROUP): %s", strerror(errno));
- return;
- }
-}
static jboolean android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz, jint netId)
{
@@ -370,7 +276,6 @@ static const JNINativeMethod gNetworkUtilMethods[] = {
{ "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter },
{ "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter },
{ "getTcpRepairWindow", "(Ljava/io/FileDescriptor;)Landroid/net/TcpRepairWindow;", (void*) android_net_utils_getTcpRepairWindow },
- { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_setupRaSocket },
{ "resNetworkSend", "(I[BII)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkSend },
{ "resNetworkQuery", "(ILjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery },
{ "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult },
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index c8e901e1e15e..ee74f6d7ab94 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -37,8 +37,6 @@ static const char* kPathWhitelist[] = {
"/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",
"/apex/com.android.tethering/javalib/framework-tethering.jar",
"/dev/null",
"/dev/socket/zygote",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 31ac2bc7407f..6d71c508bf1c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2524,17 +2524,17 @@
<permission android:name="android.permission.READ_WALLPAPER_INTERNAL"
android:protectionLevel="signature|privileged" />
- <!-- ============================================ -->
- <!-- Permissions for changing the system clock -->
- <!-- ============================================ -->
+ <!-- ===================================================== -->
+ <!-- Permissions for changing the system clock / time zone -->
+ <!-- ===================================================== -->
<eat-comment />
- <!-- Allows applications to set the system time.
- <p>Not for use by third-party applications. -->
+ <!-- Allows applications to set the system time directly.
+ <p>Not for use by third-party applications. -->
<permission android:name="android.permission.SET_TIME"
android:protectionLevel="signature|privileged" />
- <!-- Allows applications to set the system time zone.
+ <!-- Allows applications to set the system time zone directly.
<p>Not for use by third-party applications.
-->
<permission android:name="android.permission.SET_TIME_ZONE"
@@ -2542,6 +2542,20 @@
android:description="@string/permdesc_setTimeZone"
android:protectionLevel="signature|privileged" />
+ <!-- Allows telephony to suggest the time / time zone.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.SUGGEST_PHONE_TIME_AND_ZONE"
+ android:protectionLevel="signature|telephony" />
+
+ <!-- Allows applications like settings to suggest the user's manually chosen time / time zone.
+ <p>Not for use by third-party applications.
+ @hide
+ -->
+ <permission android:name="android.permission.SUGGEST_MANUAL_TIME_AND_ZONE"
+ android:protectionLevel="signature" />
+
<!-- ==================================================== -->
<!-- Permissions related to changing status bar -->
<!-- ==================================================== -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a404e2ed6f52..04d1eef9cba1 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2266,9 +2266,6 @@
<!-- Number of times to try again with the shorter interval, before backing
off until the normal polling interval. A value < 0 indicates infinite. -->
<integer name="config_ntpRetry">3</integer>
- <!-- If the time difference is greater than this threshold in milliseconds,
- then update the time. -->
- <integer name="config_ntpThreshold">5000</integer>
<!-- Timeout to wait for NTP server response in milliseconds. -->
<integer name="config_ntpTimeout">5000</integer>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2507787e2847..383fcd4753f0 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -489,7 +489,6 @@
<java-symbol type="integer" name="config_ntpPollingInterval" />
<java-symbol type="integer" name="config_ntpPollingIntervalShorter" />
<java-symbol type="integer" name="config_ntpRetry" />
- <java-symbol type="integer" name="config_ntpThreshold" />
<java-symbol type="integer" name="config_ntpTimeout" />
<java-symbol type="integer" name="config_shortPressOnPowerBehavior" />
<java-symbol type="integer" name="config_toastDefaultGravity" />
diff --git a/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
new file mode 100644
index 000000000000..9b3d0c9eaff6
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timedetector/NetworkTimeSuggestionTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timedetector;
+
+import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
+import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.util.TimestampedValue;
+
+import org.junit.Test;
+
+public class NetworkTimeSuggestionTest {
+
+ private static final TimestampedValue<Long> ARBITRARY_TIME =
+ new TimestampedValue<>(1111L, 2222L);
+
+ @Test
+ public void testEquals() {
+ NetworkTimeSuggestion one = new NetworkTimeSuggestion(ARBITRARY_TIME);
+ assertEquals(one, one);
+
+ NetworkTimeSuggestion two = new NetworkTimeSuggestion(ARBITRARY_TIME);
+ assertEquals(one, two);
+ assertEquals(two, one);
+
+ TimestampedValue<Long> differentTime = new TimestampedValue<>(
+ ARBITRARY_TIME.getReferenceTimeMillis() + 1,
+ ARBITRARY_TIME.getValue());
+ NetworkTimeSuggestion three = new NetworkTimeSuggestion(differentTime);
+ assertNotEquals(one, three);
+ assertNotEquals(three, one);
+
+ // DebugInfo must not be considered in equals().
+ one.addDebugInfo("Debug info 1");
+ two.addDebugInfo("Debug info 2");
+ assertEquals(one, two);
+ }
+
+ @Test
+ public void testParcelable() {
+ NetworkTimeSuggestion suggestion = new NetworkTimeSuggestion(ARBITRARY_TIME);
+ assertRoundTripParcelable(suggestion);
+
+ // DebugInfo should also be stored (but is not checked by equals()
+ suggestion.addDebugInfo("This is debug info");
+ NetworkTimeSuggestion rtSuggestion = roundTripParcelable(suggestion);
+ assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo());
+ }
+}
diff --git a/core/tests/coretests/src/android/text/format/TimeMigrationUtilsTest.java b/core/tests/coretests/src/android/text/format/TimeMigrationUtilsTest.java
new file mode 100644
index 000000000000..b605520c659d
--- /dev/null
+++ b/core/tests/coretests/src/android/text/format/TimeMigrationUtilsTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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.text.format;
+
+import static org.junit.Assert.assertEquals;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+import java.util.TimeZone;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TimeMigrationUtilsTest {
+
+ private static final int ONE_DAY_IN_SECONDS = 24 * 60 * 60;
+
+ private Locale mDefaultLocale;
+ private TimeZone mDefaultTimeZone;
+
+ @Before
+ public void setUp() {
+ mDefaultLocale = Locale.getDefault();
+ mDefaultTimeZone = TimeZone.getDefault();
+ }
+
+ @After
+ public void tearDown() {
+ Locale.setDefault(mDefaultLocale);
+ TimeZone.setDefault(mDefaultTimeZone);
+ }
+
+ @Test
+ public void formatMillisWithFixedFormat_fixes2038Issue() {
+ Locale.setDefault(Locale.UK);
+ TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
+
+ // The following cannot be represented properly using Time because they are outside of the
+ // supported range.
+ long y2038Issue1 = (((long) Integer.MIN_VALUE) - ONE_DAY_IN_SECONDS) * 1000L;
+ assertEquals(
+ "1901-12-12 20:45:52", TimeMigrationUtils.formatMillisWithFixedFormat(y2038Issue1));
+ long y2038Issue2 = (((long) Integer.MAX_VALUE) + ONE_DAY_IN_SECONDS) * 1000L;
+ assertEquals(
+ "2038-01-20 03:14:07", TimeMigrationUtils.formatMillisWithFixedFormat(y2038Issue2));
+ }
+
+ /**
+ * Compares TimeMigrationUtils.formatSimpleDateTime() with the code it is replacing.
+ */
+ @Test
+ public void formatMillisAsDateTime_matchesOldBehavior() {
+ // A selection of interesting locales.
+ Locale[] locales = new Locale[] {
+ Locale.US,
+ Locale.UK,
+ Locale.FRANCE,
+ Locale.JAPAN,
+ Locale.CHINA,
+ // Android supports RTL locales like arabic and arabic with latin numbers.
+ Locale.forLanguageTag("ar-AE"),
+ Locale.forLanguageTag("ar-AE-u-nu-latn"),
+ };
+ // A selection of interesting time zones.
+ String[] timeZoneIds = new String[] {
+ "UTC", "Europe/London", "America/New_York", "America/Los_Angeles", "Asia/Shanghai",
+ };
+ // Some arbitrary times when the two formatters should agree.
+ long[] timesMillis = new long[] {
+ System.currentTimeMillis(),
+ 0,
+ // The Time class only works in 32-bit range, the replacement works beyond that. To
+ // avoid messing around with offsets and complicating the test, below there are a
+ // day after / before the known limits.
+ (Integer.MIN_VALUE + ONE_DAY_IN_SECONDS) * 1000L,
+ (Integer.MAX_VALUE - ONE_DAY_IN_SECONDS) * 1000L,
+ };
+
+ for (Locale locale : locales) {
+ Locale.setDefault(locale);
+ for (String timeZoneId : timeZoneIds) {
+ TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);
+ TimeZone.setDefault(timeZone);
+ for (long timeMillis : timesMillis) {
+ Time time = new Time();
+ time.set(timeMillis);
+ String oldResult = time.format("%Y-%m-%d %H:%M:%S");
+ String newResult = TimeMigrationUtils.formatMillisWithFixedFormat(timeMillis);
+ assertEquals(
+ "locale=" + locale + ", timeZoneId=" + timeZoneId
+ + ", timeMillis=" + timeMillis,
+ oldResult, newResult);
+ }
+ }
+ }
+ }
+}
diff --git a/core/xsd/permission.xsd b/core/xsd/permission.xsd
index 9520db767350..cc01a31224bc 100644
--- a/core/xsd/permission.xsd
+++ b/core/xsd/permission.xsd
@@ -126,12 +126,12 @@
</xs:complexType>
<xs:complexType name="privapp-permissions">
<xs:sequence>
- <xs:element name="permission" maxOccurs="unbounded">
+ <xs:element name="permission" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
</xs:element>
- <xs:element name="deny-permission" maxOccurs="unbounded">
+ <xs:element name="deny-permission" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
@@ -141,12 +141,12 @@
</xs:complexType>
<xs:complexType name="oem-permissions">
<xs:sequence>
- <xs:element name="permission" maxOccurs="unbounded">
+ <xs:element name="permission" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
</xs:element>
- <xs:element name="deny-permission" maxOccurs="unbounded">
+ <xs:element name="deny-permission" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml
index ba877f8d0d02..cc1ce9bbeecb 100644
--- a/data/etc/com.android.settings.xml
+++ b/data/etc/com.android.settings.xml
@@ -42,8 +42,8 @@
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.READ_SEARCH_INDEXABLES"/>
<permission name="android.permission.REBOOT"/>
- <permission name="android.permission.SET_TIME"/>
<permission name="android.permission.STATUS_BAR"/>
+ <permission name="android.permission.SUGGEST_MANUAL_TIME_AND_ZONE"/>
<permission name="android.permission.TETHER_PRIVILEGED"/>
<permission name="android.permission.USE_RESERVED_DISK"/>
<permission name="android.permission.USER_ACTIVITY"/>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index c9097341a18e..0756647d5774 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -155,12 +155,12 @@ applications that come with the platform
<permission name="android.permission.REGISTER_CALL_PROVIDER"/>
<permission name="android.permission.REGISTER_SIM_SUBSCRIPTION"/>
<permission name="android.permission.SEND_RESPOND_VIA_MESSAGE"/>
- <permission name="android.permission.SET_TIME"/>
<permission name="android.permission.SET_TIME_ZONE"/>
<permission name="android.permission.SHUTDOWN"/>
<permission name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"/>
<permission name="android.permission.STATUS_BAR"/>
<permission name="android.permission.STOP_APP_SWITCHES"/>
+ <permission name="android.permission.SUGGEST_PHONE_TIME_AND_ZONE"/>
<permission name="android.permission.UPDATE_APP_OPS_STATS"/>
<permission name="android.permission.UPDATE_DEVICE_STATS"/>
<permission name="android.permission.UPDATE_LOCK"/>
diff --git a/media/java/android/media/tv/DvbDeviceInfo.java b/media/java/android/media/tv/DvbDeviceInfo.java
index a574fe18fb63..96c852812a74 100644
--- a/media/java/android/media/tv/DvbDeviceInfo.java
+++ b/media/java/android/media/tv/DvbDeviceInfo.java
@@ -16,6 +16,8 @@
package android.media.tv;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
@@ -26,10 +28,11 @@ import android.util.Log;
*
* @hide
*/
+@SystemApi
public final class DvbDeviceInfo implements Parcelable {
static final String TAG = "DvbDeviceInfo";
- public static final @android.annotation.NonNull Parcelable.Creator<DvbDeviceInfo> CREATOR =
+ public static final @NonNull Parcelable.Creator<DvbDeviceInfo> CREATOR =
new Parcelable.Creator<DvbDeviceInfo>() {
@Override
public DvbDeviceInfo createFromParcel(Parcel source) {
@@ -86,7 +89,7 @@ public final class DvbDeviceInfo implements Parcelable {
}
@Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mAdapterId);
dest.writeInt(mDeviceId);
}
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index d22a29893540..854ea43f17c3 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -103,6 +103,12 @@ public final class TvInputManager {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
+ @IntDef({DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_FRONTEND})
+ public @interface DvbDeviceType {}
+
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
@IntDef({VIDEO_UNAVAILABLE_REASON_UNKNOWN, VIDEO_UNAVAILABLE_REASON_TUNING,
VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL, VIDEO_UNAVAILABLE_REASON_BUFFERING,
VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY})
@@ -1663,6 +1669,9 @@ public final class TvInputManager {
* @return the list of {@link DvbDeviceInfo} objects representing available DVB devices.
* @hide
*/
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.DVB_DEVICE)
+ @NonNull
public List<DvbDeviceInfo> getDvbDeviceList() {
try {
return mService.getDvbDeviceList();
@@ -1676,19 +1685,24 @@ public final class TvInputManager {
* {@link DvbDeviceInfo}
*
* @param info A {@link DvbDeviceInfo} to open a DVB device.
- * @param device A DVB device. The DVB device can be {@link #DVB_DEVICE_DEMUX},
+ * @param deviceType A DVB device type. The type can be {@link #DVB_DEVICE_DEMUX},
* {@link #DVB_DEVICE_DVR} or {@link #DVB_DEVICE_FRONTEND}.
* @return a {@link ParcelFileDescriptor} of a specified DVB device for a given
- * {@link DvbDeviceInfo}, or {@code null} if the given {@link DvbDeviceInfo} was invalid
- * or the specified DVB device was busy with a previous request.
+ * {@link DvbDeviceInfo}, or {@code null} if the given {@link DvbDeviceInfo}
+ * failed to open.
+ * @throws IllegalArgumentException if {@code deviceType} is invalid or the device is not found.
* @hide
*/
- public ParcelFileDescriptor openDvbDevice(DvbDeviceInfo info, int device) {
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.DVB_DEVICE)
+ @Nullable
+ public ParcelFileDescriptor openDvbDevice(@NonNull DvbDeviceInfo info,
+ @DvbDeviceType int deviceType) {
try {
- if (DVB_DEVICE_START > device || DVB_DEVICE_END < device) {
- throw new IllegalArgumentException("Invalid DVB device: " + device);
+ if (DVB_DEVICE_START > deviceType || DVB_DEVICE_END < deviceType) {
+ throw new IllegalArgumentException("Invalid DVB device: " + deviceType);
}
- return mService.openDvbDevice(info, device);
+ return mService.openDvbDevice(info, deviceType);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 8d420e2c5598..05aaa82f8ac8 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -743,8 +743,10 @@ status_t JMediaCodec::getCodecInfo(JNIEnv *env, jobject *codecInfoObject) const
}
status_t JMediaCodec::getMetrics(JNIEnv *, MediaAnalyticsItem * &reply) const {
-
- status_t status = mCodec->getMetrics(reply);
+ mediametrics_handle_t reply2 = MediaAnalyticsItem::convert(reply);
+ status_t status = mCodec->getMetrics(reply2);
+ // getMetrics() updates reply2, pass the converted update along to our caller.
+ reply = MediaAnalyticsItem::convert(reply2);
return status;
}
@@ -1848,7 +1850,7 @@ android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
}
// get what we have for the metrics from the codec
- MediaAnalyticsItem *item = NULL;
+ MediaAnalyticsItem *item = 0;
status_t err = codec->getMetrics(env, item);
if (err != OK) {
@@ -1860,7 +1862,7 @@ android_media_MediaCodec_native_getMetrics(JNIEnv *env, jobject thiz)
// housekeeping
delete item;
- item = NULL;
+ item = 0;
return mybundle;
}
diff --git a/mms/java/android/telephony/MmsManager.java b/mms/java/android/telephony/MmsManager.java
index 4bcf04691652..65542673a607 100644
--- a/mms/java/android/telephony/MmsManager.java
+++ b/mms/java/android/telephony/MmsManager.java
@@ -97,22 +97,4 @@ public class MmsManager {
// Ignore it
}
}
-
- /**
- * Get carrier-dependent configuration values.
- *
- * @param subId the subscription id
- * @return bundle key/values pairs of configuration values
- */
- public Bundle getCarrierConfigValues(int subId) {
- try {
- IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
- if (iMms != null) {
- return iMms.getCarrierConfigValues(subId);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- return null;
- }
}
diff --git a/mms/java/com/android/internal/telephony/IMms.aidl b/mms/java/com/android/internal/telephony/IMms.aidl
index fa5073ef1c7e..8be511186800 100644
--- a/mms/java/com/android/internal/telephony/IMms.aidl
+++ b/mms/java/com/android/internal/telephony/IMms.aidl
@@ -60,13 +60,6 @@ interface IMms {
in PendingIntent downloadedIntent);
/**
- * Get carrier-dependent configuration values.
- *
- * @param subId the SIM id
- */
- Bundle getCarrierConfigValues(int subId);
-
- /**
* Import a text message into system's SMS store
*
* @param callingPkg the calling app's package name
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 08552cbfd394..596f62fad23e 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -45,9 +45,9 @@ android_library {
// Due to b/143733063, APK can't access a jni lib that is in APEX (but not in the APK).
cc_library {
- name: "libtetheroffloadjni",
+ name: "libtetherutilsjni",
srcs: [
- "jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp",
+ "jni/android_net_util_TetheringUtils.cpp",
],
shared_libs: [
"libcgrouprc",
@@ -87,7 +87,7 @@ java_defaults {
"libcgrouprc",
"libnativehelper_compat_libc++",
"libvndksupport",
- "libtetheroffloadjni",
+ "libtetherutilsjni",
],
resource_dirs: [
"res",
diff --git a/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp b/packages/Tethering/jni/android_net_util_TetheringUtils.cpp
index 663154a49048..1cf8f988432c 100644
--- a/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
+++ b/packages/Tethering/jni/android_net_util_TetheringUtils.cpp
@@ -19,13 +19,16 @@
#include <hidl/HidlSupport.h>
#include <jni.h>
#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedUtfChars.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netlink.h>
+#include <net/if.h>
+#include <netinet/icmp6.h>
#include <sys/socket.h>
#include <android-base/unique_fd.h>
#include <android/hardware/tetheroffload/config/1.0/IOffloadConfig.h>
-#define LOG_TAG "OffloadHardwareInterface"
+#define LOG_TAG "TetheringUtils"
#include <utils/Log.h>
namespace android {
@@ -87,7 +90,7 @@ hidl_handle handleFromFileDescriptor(base::unique_fd fd) {
} // namespace
-static jboolean android_server_connectivity_tethering_OffloadHardwareInterface_configOffload(
+static jboolean android_net_util_configOffload(
JNIEnv* /* env */) {
sp<IOffloadConfig> configInterface = IOffloadConfig::getService();
if (configInterface.get() == nullptr) {
@@ -130,18 +133,109 @@ static jboolean android_server_connectivity_tethering_OffloadHardwareInterface_c
return rval;
}
+static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd,
+ jint ifIndex)
+{
+ static const int kLinkLocalHopLimit = 255;
+
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+
+ // Set an ICMPv6 filter that only passes Router Solicitations.
+ struct icmp6_filter rs_only;
+ ICMP6_FILTER_SETBLOCKALL(&rs_only);
+ ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &rs_only);
+ socklen_t len = sizeof(rs_only);
+ if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &rs_only, len) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "setsockopt(ICMP6_FILTER): %s", strerror(errno));
+ return;
+ }
+
+ // Most/all of the rest of these options can be set via Java code, but
+ // because we're here on account of setting an icmp6_filter go ahead
+ // and do it all natively for now.
+
+ // Set the multicast hoplimit to 255 (link-local only).
+ int hops = kLinkLocalHopLimit;
+ len = sizeof(hops);
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, len) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "setsockopt(IPV6_MULTICAST_HOPS): %s", strerror(errno));
+ return;
+ }
+
+ // Set the unicast hoplimit to 255 (link-local only).
+ hops = kLinkLocalHopLimit;
+ len = sizeof(hops);
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, len) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "setsockopt(IPV6_UNICAST_HOPS): %s", strerror(errno));
+ return;
+ }
+
+ // Explicitly disable multicast loopback.
+ int off = 0;
+ len = sizeof(off);
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, len) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "setsockopt(IPV6_MULTICAST_LOOP): %s", strerror(errno));
+ return;
+ }
+
+ // Specify the IPv6 interface to use for outbound multicast.
+ len = sizeof(ifIndex);
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifIndex, len) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "setsockopt(IPV6_MULTICAST_IF): %s", strerror(errno));
+ return;
+ }
+
+ // Additional options to be considered:
+ // - IPV6_TCLASS
+ // - IPV6_RECVPKTINFO
+ // - IPV6_RECVHOPLIMIT
+
+ // Bind to [::].
+ const struct sockaddr_in6 sin6 = {
+ .sin6_family = AF_INET6,
+ .sin6_port = 0,
+ .sin6_flowinfo = 0,
+ .sin6_addr = IN6ADDR_ANY_INIT,
+ .sin6_scope_id = 0,
+ };
+ auto sa = reinterpret_cast<const struct sockaddr *>(&sin6);
+ len = sizeof(sin6);
+ if (bind(fd, sa, len) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "bind(IN6ADDR_ANY): %s", strerror(errno));
+ return;
+ }
+
+ // Join the all-routers multicast group, ff02::2%index.
+ struct ipv6_mreq all_rtrs = {
+ .ipv6mr_multiaddr = {{{0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2}}},
+ .ipv6mr_interface = ifIndex,
+ };
+ len = sizeof(all_rtrs);
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &all_rtrs, len) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "setsockopt(IPV6_JOIN_GROUP): %s", strerror(errno));
+ return;
+ }
+}
+
/*
* JNI registration.
*/
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- { "configOffload", "()Z",
- (void*) android_server_connectivity_tethering_OffloadHardwareInterface_configOffload },
+ { "configOffload", "()Z", (void*) android_net_util_configOffload },
+ { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_util_setupRaSocket },
};
-int register_android_server_connectivity_tethering_OffloadHardwareInterface(JNIEnv* env) {
+int register_android_net_util_TetheringUtils(JNIEnv* env) {
return jniRegisterNativeMethods(env,
- "com/android/server/connectivity/tethering/OffloadHardwareInterface",
+ "android/net/util/TetheringUtils",
gMethods, NELEM(gMethods));
}
@@ -152,7 +246,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
return JNI_ERR;
}
- if (register_android_server_connectivity_tethering_OffloadHardwareInterface(env) < 0) {
+ if (register_android_net_util_TetheringUtils(env) < 0) {
return JNI_ERR;
}
diff --git a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
index 414741309ef0..4396cdb92621 100644
--- a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
+++ b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
@@ -30,6 +30,7 @@ import android.net.LinkAddress;
import android.net.NetworkUtils;
import android.net.TrafficStats;
import android.net.util.InterfaceParams;
+import android.net.util.TetheringUtils;
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructTimeval;
@@ -613,7 +614,7 @@ public class RouterAdvertisementDaemon {
mSocket, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(send_timout_ms));
Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mInterface.name);
NetworkUtils.protectFromVpn(mSocket);
- NetworkUtils.setupRaSocket(mSocket, mInterface.index);
+ TetheringUtils.setupRaSocket(mSocket, mInterface.index);
} catch (ErrnoException | IOException e) {
Log.e(TAG, "Failed to create RA daemon socket: " + e);
return false;
diff --git a/packages/Tethering/src/android/net/util/TetheringUtils.java b/packages/Tethering/src/android/net/util/TetheringUtils.java
new file mode 100644
index 000000000000..2fb73ced8884
--- /dev/null
+++ b/packages/Tethering/src/android/net/util/TetheringUtils.java
@@ -0,0 +1,42 @@
+/*
+ * 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.net.util;
+
+import java.io.FileDescriptor;
+import java.net.SocketException;
+
+/**
+ * Native methods for tethering utilization.
+ *
+ * {@hide}
+ */
+public class TetheringUtils {
+
+ /**
+ * Offload management process need to know conntrack rules to support NAT, but it may not have
+ * permission to create netlink netfilter sockets. Create two netlink netfilter sockets and
+ * share them with offload management process.
+ */
+ public static native boolean configOffload();
+
+ /**
+ * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements.
+ * @param fd the socket's {@link FileDescriptor}.
+ * @param ifIndex the interface index.
+ */
+ public static native void setupRaSocket(FileDescriptor fd, int ifIndex)
+ throws SocketException;
+}
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 00a677338b1b..85164edf3c5b 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -24,6 +24,7 @@ import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
import android.net.util.SharedLog;
+import android.net.util.TetheringUtils;
import android.os.Handler;
import android.os.RemoteException;
import android.system.OsConstants;
@@ -47,8 +48,6 @@ public class OffloadHardwareInterface {
private static final String NO_IPV4_ADDRESS = "";
private static final String NO_IPV4_GATEWAY = "";
- private static native boolean configOffload();
-
private final Handler mHandler;
private final SharedLog mLog;
private IOffloadControl mOffloadControl;
@@ -107,8 +106,6 @@ public class OffloadHardwareInterface {
public OffloadHardwareInterface(Handler h, SharedLog log) {
mHandler = h;
mLog = log.forSubComponent(TAG);
-
- System.loadLibrary("tetheroffloadjni");
}
/** Get default value indicating whether offload is supported. */
@@ -118,7 +115,7 @@ public class OffloadHardwareInterface {
/** Configure offload management process. */
public boolean initOffloadConfig() {
- return configOffload();
+ return TetheringUtils.configOffload();
}
/** Initialize the tethering offload HAL. */
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index 3116321e0954..f3b8cbc63757 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -633,8 +633,7 @@ public class Tethering {
reportTetherStateChanged(mTetherStatesParcel);
final Intent bcast = new Intent(ACTION_TETHER_STATE_CHANGED);
- bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
- | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
bcast.putStringArrayListExtra(EXTRA_AVAILABLE_TETHER, availableList);
bcast.putStringArrayListExtra(EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList);
bcast.putStringArrayListExtra(EXTRA_ACTIVE_TETHER, tetherList);
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
index ba30845e6348..1d5998680287 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
@@ -84,6 +84,7 @@ public class TetheringService extends Service {
*/
@VisibleForTesting
public Tethering makeTethering(TetheringDependencies deps) {
+ System.loadLibrary("tetherutilsjni");
return new Tethering(deps);
}
diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp
index 81a0548cd718..53782fed1c50 100644
--- a/packages/Tethering/tests/unit/Android.bp
+++ b/packages/Tethering/tests/unit/Android.bp
@@ -20,7 +20,11 @@ android_test {
srcs: [
"src/**/*.java",
],
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "mts",
+ ],
+ compile_multilib: "both",
static_libs: [
"androidx.test.rules",
"frameworks-base-testutils",
diff --git a/services/Android.bp b/services/Android.bp
index 53d792d1033a..80452f19e6c1 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -121,6 +121,12 @@ droidstubs {
"framework-all",
],
visibility: ["//visibility:private"],
+ check_api: {
+ current: {
+ api_file: "api/current.txt",
+ removed_api_file: "api/removed.txt",
+ },
+ },
}
java_library {
diff --git a/services/api/current.txt b/services/api/current.txt
new file mode 100644
index 000000000000..d802177e249b
--- /dev/null
+++ b/services/api/current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/api/removed.txt b/services/api/removed.txt
new file mode 100644
index 000000000000..d802177e249b
--- /dev/null
+++ b/services/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index 9dead161390f..aeb3e7fd94de 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -41,7 +41,7 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
-import android.text.format.Time;
+import android.text.format.TimeMigrationUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
@@ -582,11 +582,9 @@ public final class DropBoxManagerService extends SystemService {
}
int numFound = 0, numArgs = searchArgs.size();
- Time time = new Time();
out.append("\n");
for (EntryFile entry : mAllFiles.contents) {
- time.set(entry.timestampMillis);
- String date = time.format("%Y-%m-%d %H:%M:%S");
+ String date = TimeMigrationUtils.formatMillisWithFixedFormat(entry.timestampMillis);
boolean match = true;
for (int i = 0; i < numArgs && match; i++) {
String arg = searchArgs.get(i);
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index c0f10a3c86e1..fe154ed8d396 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -137,11 +137,6 @@ public class MmsServiceBroker extends SystemService {
}
@Override
- public Bundle getCarrierConfigValues(int subId) throws RemoteException {
- return null;
- }
-
- @Override
public Uri importTextMessage(String callingPkg, String address, int type, String text,
long timestampMillis, boolean seen, boolean read) throws RemoteException {
return null;
@@ -370,12 +365,6 @@ public class MmsServiceBroker extends SystemService {
}
@Override
- public Bundle getCarrierConfigValues(int subId) throws RemoteException {
- Slog.d(TAG, "getCarrierConfigValues() by " + getCallingPackageName());
- return getServiceGuarded().getCarrierConfigValues(subId);
- }
-
- @Override
public Uri importTextMessage(String callingPkg, String address, int type, String text,
long timestampMillis, boolean seen, boolean read) throws RemoteException {
if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
index 39be311e902d..cfe56052118f 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
@@ -18,6 +18,8 @@ package com.android.server;
import android.app.AlarmManager;
import android.app.PendingIntent;
+import android.app.timedetector.NetworkTimeSuggestion;
+import android.app.timedetector.TimeDetector;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -35,10 +37,10 @@ import android.os.Message;
import android.os.PowerManager;
import android.os.SystemClock;
import android.provider.Settings;
-import android.telephony.TelephonyManager;
import android.util.Log;
import android.util.NtpTrustedTime;
import android.util.TimeUtils;
+import android.util.TimestampedValue;
import com.android.internal.util.DumpUtils;
@@ -46,21 +48,19 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
/**
- * Monitors the network time and updates the system time if it is out of sync
- * and there hasn't been any NITZ update from the carrier recently.
- * If looking up the network time fails for some reason, it tries a few times with a short
- * interval and then resets to checking on longer intervals.
- * <p>
- * If the user enables AUTO_TIME, it will check immediately for the network time, if NITZ wasn't
- * available.
- * </p>
+ * Monitors the network time. If looking up the network time fails for some reason, it tries a few
+ * times with a short interval and then resets to checking on longer intervals.
+ *
+ * <p>When available, the time is always suggested to the {@link
+ * com.android.server.timedetector.TimeDetectorService} where it may be used to set the device
+ * system clock, depending on user settings and what other signals are available.
*/
public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeUpdateService {
private static final String TAG = "NetworkTimeUpdateService";
private static final boolean DBG = false;
- private static final int EVENT_AUTO_TIME_CHANGED = 1;
+ private static final int EVENT_AUTO_TIME_ENABLED = 1;
private static final int EVENT_POLL_NETWORK_TIME = 2;
private static final int EVENT_NETWORK_CHANGED = 3;
@@ -69,20 +69,19 @@ public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeU
private static final int POLL_REQUEST = 0;
- private static final long NOT_SET = -1;
- private long mNitzTimeSetTime = NOT_SET;
private Network mDefaultNetwork = null;
private final Context mContext;
private final NtpTrustedTime mTime;
private final AlarmManager mAlarmManager;
+ private final TimeDetector mTimeDetector;
private final ConnectivityManager mCM;
private final PendingIntent mPendingPollIntent;
private final PowerManager.WakeLock mWakeLock;
// NTP lookup is done on this thread and handler
private Handler mHandler;
- private SettingsObserver mSettingsObserver;
+ private AutoTimeSettingObserver mAutoTimeSettingObserver;
private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
// Normal polling frequency
@@ -91,8 +90,6 @@ public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeU
private final long mPollingIntervalShorterMs;
// Number of times to try again
private final int mTryAgainTimesMax;
- // If the time difference is greater than this threshold, then update the time.
- private final int mTimeErrorThresholdMs;
// Keeps track of how many quick attempts were made to fetch NTP time.
// During bootup, the network may not have been up yet, or it's taking time for the
// connection to happen.
@@ -102,6 +99,7 @@ public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeU
mContext = context;
mTime = NtpTrustedTime.getInstance(context);
mAlarmManager = mContext.getSystemService(AlarmManager.class);
+ mTimeDetector = mContext.getSystemService(TimeDetector.class);
mCM = mContext.getSystemService(ConnectivityManager.class);
Intent pollIntent = new Intent(ACTION_POLL, null);
@@ -113,8 +111,6 @@ public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeU
com.android.internal.R.integer.config_ntpPollingIntervalShorter);
mTryAgainTimesMax = mContext.getResources().getInteger(
com.android.internal.R.integer.config_ntpRetry);
- mTimeErrorThresholdMs = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpThreshold);
mWakeLock = context.getSystemService(PowerManager.class).newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, TAG);
@@ -122,7 +118,6 @@ public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeU
@Override
public void systemRunning() {
- registerForTelephonyIntents();
registerForAlarms();
HandlerThread thread = new HandlerThread(TAG);
@@ -131,14 +126,9 @@ public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeU
mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
- mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
- mSettingsObserver.observe(mContext);
- }
-
- private void registerForTelephonyIntents() {
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(TelephonyManager.ACTION_NETWORK_SET_TIME);
- mContext.registerReceiver(mNitzReceiver, intentFilter);
+ mAutoTimeSettingObserver = new AutoTimeSettingObserver(mContext, mHandler,
+ EVENT_AUTO_TIME_ENABLED);
+ mAutoTimeSettingObserver.observe();
}
private void registerForAlarms() {
@@ -152,8 +142,7 @@ public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeU
}
private void onPollNetworkTime(int event) {
- // If Automatic time is not set, don't bother. Similarly, if we don't
- // have any default network, don't bother.
+ // If we don't have any default network, don't bother.
if (mDefaultNetwork == null) return;
mWakeLock.acquire();
try {
@@ -173,10 +162,12 @@ public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeU
if (mTime.getCacheAge() < mPollingIntervalMs) {
// Obtained fresh fix; schedule next normal update
resetAlarm(mPollingIntervalMs);
- if (isAutomaticTimeRequested()) {
- updateSystemClock(event);
- }
+ // Suggest the time to the time detector. It may choose use it to set the system clock.
+ TimestampedValue<Long> timeSignal = mTime.getCachedNtpTimeSignal();
+ NetworkTimeSuggestion timeSuggestion = new NetworkTimeSuggestion(timeSignal);
+ timeSuggestion.addDebugInfo("Origin: NetworkTimeUpdateServiceImpl. event=" + event);
+ mTimeDetector.suggestNetworkTime(timeSuggestion);
} else {
// No fresh fix; schedule retry
mTryAgainCounter++;
@@ -190,36 +181,6 @@ public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeU
}
}
- private long getNitzAge() {
- if (mNitzTimeSetTime == NOT_SET) {
- return Long.MAX_VALUE;
- } else {
- return SystemClock.elapsedRealtime() - mNitzTimeSetTime;
- }
- }
-
- /**
- * Consider updating system clock based on current NTP fix, if requested by
- * user, significant enough delta, and we don't have a recent NITZ.
- */
- private void updateSystemClock(int event) {
- final boolean forceUpdate = (event == EVENT_AUTO_TIME_CHANGED);
- if (!forceUpdate) {
- if (getNitzAge() < mPollingIntervalMs) {
- if (DBG) Log.d(TAG, "Ignoring NTP update due to recent NITZ");
- return;
- }
-
- final long skew = Math.abs(mTime.currentTimeMillis() - System.currentTimeMillis());
- if (skew < mTimeErrorThresholdMs) {
- if (DBG) Log.d(TAG, "Ignoring NTP update due to low skew");
- return;
- }
- }
-
- SystemClock.setCurrentTimeMillis(mTime.currentTimeMillis());
- }
-
/**
* Cancel old alarm and starts a new one for the specified interval.
*
@@ -232,27 +193,6 @@ public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeU
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
}
- /**
- * Checks if the user prefers to automatically set the time.
- */
- private boolean isAutomaticTimeRequested() {
- return Settings.Global.getInt(
- mContext.getContentResolver(), Settings.Global.AUTO_TIME, 0) != 0;
- }
-
- /** Receiver for Nitz time events */
- private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (DBG) Log.d(TAG, "Received " + action);
- if (TelephonyManager.ACTION_NETWORK_SET_TIME.equals(action)) {
- mNitzTimeSetTime = SystemClock.elapsedRealtime();
- }
- }
- };
-
/** Handler to do the network accesses on */
private class MyHandler extends Handler {
@@ -263,7 +203,7 @@ public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeU
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case EVENT_AUTO_TIME_CHANGED:
+ case EVENT_AUTO_TIME_ENABLED:
case EVENT_POLL_NETWORK_TIME:
case EVENT_NETWORK_CHANGED:
onPollNetworkTime(msg.what);
@@ -287,27 +227,42 @@ public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeU
}
}
- /** Observer to watch for changes to the AUTO_TIME setting */
- private static class SettingsObserver extends ContentObserver {
+ /**
+ * Observer to watch for changes to the AUTO_TIME setting. It only triggers when the setting
+ * is enabled.
+ */
+ private static class AutoTimeSettingObserver extends ContentObserver {
- private int mMsg;
- private Handler mHandler;
+ private final Context mContext;
+ private final int mMsg;
+ private final Handler mHandler;
- SettingsObserver(Handler handler, int msg) {
+ AutoTimeSettingObserver(Context context, Handler handler, int msg) {
super(handler);
+ mContext = context;
mHandler = handler;
mMsg = msg;
}
- void observe(Context context) {
- ContentResolver resolver = context.getContentResolver();
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
false, this);
}
@Override
public void onChange(boolean selfChange) {
- mHandler.obtainMessage(mMsg).sendToTarget();
+ if (isAutomaticTimeEnabled()) {
+ mHandler.obtainMessage(mMsg).sendToTarget();
+ }
+ }
+
+ /**
+ * Checks if the user prefers to automatically set the time.
+ */
+ private boolean isAutomaticTimeEnabled() {
+ ContentResolver resolver = mContext.getContentResolver();
+ return Settings.Global.getInt(resolver, Settings.Global.AUTO_TIME, 0) != 0;
}
}
@@ -319,8 +274,6 @@ public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeU
pw.print("\nPollingIntervalShorterMs: ");
TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
- pw.print("TimeErrorThresholdMs: ");
- TimeUtils.formatDuration(mTimeErrorThresholdMs, pw);
pw.println("\nTryAgainCounter: " + mTryAgainCounter);
pw.println("NTP cache age: " + mTime.getCacheAge());
pw.println("NTP cache certainty: " + mTime.getCacheCertainty());
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index b5ecd196ba8a..ed006b9bef39 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1610,7 +1610,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
handleRemoveListLocked();
}
- broadcastDataConnectionFailed(apnType, subId);
}
public void notifyCellLocation(Bundle cellLocation) {
@@ -2259,13 +2258,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
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(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId);
- mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
- }
-
private void enforceNotifyPermissionOrCarrierPrivilege(String method) {
if (checkNotifyPermission()) {
return;
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index fa8c48bdc7f7..a89daff2d3bb 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -86,7 +86,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
import android.provider.Settings;
-import android.text.format.Time;
+import android.text.format.TimeMigrationUtils;
import android.util.EventLog;
import android.util.Log;
import android.util.Pair;
@@ -1987,9 +1987,7 @@ public class SyncManager {
if (time == 0) {
return "N/A";
}
- Time tobj = new Time();
- tobj.set(time);
- return tobj.format("%Y-%m-%d %H:%M:%S");
+ return TimeMigrationUtils.formatMillisWithFixedFormat(time);
}
private final static Comparator<SyncOperation> sOpDumpComparator = (op1, op2) -> {
@@ -2555,9 +2553,7 @@ public class SyncManager {
accountKey = "Unknown";
}
final long elapsedTime = item.elapsedTime;
- final Time time = new Time();
final long eventTime = item.eventTime;
- time.set(eventTime);
final String key = authorityName + "/" + accountKey;
final Long lastEventTime = lastTimeMap.get(key);
@@ -2622,9 +2618,7 @@ public class SyncManager {
authorityName = "Unknown";
accountKey = "Unknown";
}
- final Time time = new Time();
final long eventTime = item.eventTime;
- time.set(eventTime);
pw.printf(" #%-3d: %s %8s ",
i + 1,
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index eb5d472f7fbc..e655b35d930f 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -29,7 +29,7 @@ import android.net.Network;
import android.net.Uri;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.text.format.Time;
+import android.text.format.TimeMigrationUtils;
import android.util.ArraySet;
import android.util.Pair;
import android.util.Slog;
@@ -1643,17 +1643,13 @@ public final class JobStatus {
if (numFailures != 0) {
pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
}
- final Time t = new Time();
- final String format = "%Y-%m-%d %H:%M:%S";
if (mLastSuccessfulRunTime != 0) {
pw.print(prefix); pw.print("Last successful run: ");
- t.set(mLastSuccessfulRunTime);
- pw.println(t.format(format));
+ pw.println(TimeMigrationUtils.formatMillisWithFixedFormat(mLastSuccessfulRunTime));
}
if (mLastFailedRunTime != 0) {
pw.print(prefix); pw.print("Last failed run: ");
- t.set(mLastFailedRunTime);
- pw.println(t.format(format));
+ pw.println(TimeMigrationUtils.formatMillisWithFixedFormat(mLastFailedRunTime));
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 2d8a2acd575f..ebba128b5f28 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -79,7 +79,7 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.text.TextUtils;
-import android.text.format.Time;
+import android.text.format.TimeMigrationUtils;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.KeyValueListParser;
@@ -3981,9 +3981,7 @@ public class ShortcutService extends IShortcutService.Stub {
}
static String formatTime(long time) {
- Time tobj = new Time();
- tobj.set(time);
- return tobj.format("%Y-%m-%d %H:%M:%S");
+ return TimeMigrationUtils.formatMillisWithFixedFormat(time);
}
private void dumpCurrentTime(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 172367a128cc..b7d63609cff9 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.timedetector.ITimeDetectorService;
import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.ContentResolver;
import android.content.Context;
@@ -105,6 +106,14 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
mHandler.post(() -> mTimeDetectorStrategy.suggestManualTime(timeSignal));
}
+ @Override
+ public void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal) {
+ enforceSuggestNetworkTimePermission();
+ Objects.requireNonNull(timeSignal);
+
+ mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(timeSignal));
+ }
+
@VisibleForTesting
public void handleAutoTimeDetectionToggle() {
mHandler.post(mTimeDetectorStrategy::handleAutoTimeDetectionChanged);
@@ -119,10 +128,20 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
}
private void enforceSuggestPhoneTimePermission() {
- mContext.enforceCallingPermission(android.Manifest.permission.SET_TIME, "set time");
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE,
+ "suggest phone time and time zone");
}
private void enforceSuggestManualTimePermission() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SET_TIME, "set time");
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE,
+ "suggest manual time and time zone");
+ }
+
+ private void enforceSuggestNetworkTimePermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.SET_TIME,
+ "set time");
}
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index 0a6c2e776072..b4f4eca5f188 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -19,6 +19,7 @@ package com.android.server.timedetector;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
import android.util.TimestampedValue;
@@ -86,6 +87,9 @@ public interface TimeDetectorStrategy {
/** Process the suggested manually entered time. */
void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion);
+ /** Process the suggested time from network sources. */
+ void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion);
+
/** Handle the auto-time setting being toggled on or off. */
void handleAutoTimeDetectionChanged();
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index c50248d4b402..02656eaf5c6c 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
import android.telephony.TelephonyManager;
@@ -32,6 +33,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.timezonedetector.ArrayMapWithHistory;
+import com.android.server.timezonedetector.ReferenceWithHistory;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -56,11 +58,11 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
/** 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. */
+ /** Phone and network suggestions older than this value are considered too old to be used. */
@VisibleForTesting
- static final long PHONE_MAX_AGE_MILLIS = PHONE_BUCKET_COUNT * PHONE_BUCKET_SIZE_MILLIS;
+ static final long MAX_UTC_TIME_AGE_MILLIS = PHONE_BUCKET_COUNT * PHONE_BUCKET_SIZE_MILLIS;
- @IntDef({ ORIGIN_PHONE, ORIGIN_MANUAL })
+ @IntDef({ ORIGIN_PHONE, ORIGIN_MANUAL, ORIGIN_NETWORK })
@Retention(RetentionPolicy.SOURCE)
public @interface Origin {}
@@ -72,6 +74,10 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
@Origin
private static final int ORIGIN_MANUAL = 2;
+ /** Used when a time value originated from a network signal. */
+ @Origin
+ private static final int ORIGIN_NETWORK = 3;
+
/**
* 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
@@ -101,9 +107,13 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
* will have a small number of telephony devices and phoneIds are assumed to be stable.
*/
@GuardedBy("this")
- private ArrayMapWithHistory<Integer, PhoneTimeSuggestion> mSuggestionByPhoneId =
+ private final ArrayMapWithHistory<Integer, PhoneTimeSuggestion> mSuggestionByPhoneId =
new ArrayMapWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
+ @GuardedBy("this")
+ private final ReferenceWithHistory<NetworkTimeSuggestion> mLastNetworkSuggestion =
+ new ReferenceWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
+
@Override
public void initialize(@NonNull Callback callback) {
mCallback = callback;
@@ -122,6 +132,19 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
}
@Override
+ public synchronized void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion) {
+ if (!validateSuggestionTime(timeSuggestion.getUtcTime(), timeSuggestion)) {
+ return;
+ }
+ mLastNetworkSuggestion.set(timeSuggestion);
+
+ // Now perform auto time detection. The new suggestion may be used to modify the system
+ // clock.
+ String reason = "New network time suggested. timeSuggestion=" + timeSuggestion;
+ doAutoTimeDetection(reason);
+ }
+
+ @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,
@@ -167,6 +190,12 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
ipw.increaseIndent(); // level 1
ipw.println("mLastAutoSystemClockTimeSet=" + mLastAutoSystemClockTimeSet);
+ ipw.println("mCallback.isAutoTimeDetectionEnabled()="
+ + mCallback.isAutoTimeDetectionEnabled());
+ ipw.println("mCallback.elapsedRealtimeMillis()=" + mCallback.elapsedRealtimeMillis());
+ ipw.println("mCallback.systemClockMillis()=" + mCallback.systemClockMillis());
+ ipw.println("mCallback.systemClockUpdateThresholdMillis()="
+ + mCallback.systemClockUpdateThresholdMillis());
ipw.println("Time change log:");
ipw.increaseIndent(); // level 2
@@ -178,6 +207,11 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
mSuggestionByPhoneId.dump(ipw);
ipw.decreaseIndent(); // level 2
+ ipw.println("Network suggestion history:");
+ ipw.increaseIndent(); // level 2
+ mLastNetworkSuggestion.dump(ipw);
+ ipw.decreaseIndent(); // level 2
+
ipw.decreaseIndent(); // level 1
ipw.flush();
}
@@ -247,23 +281,34 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
return;
}
+ // Android devices currently prioritize any telephony over network signals. There are
+ // carrier compliance tests that would need to be changed before we could ignore NITZ or
+ // prefer NTP generally. This check is cheap on devices without phone hardware.
PhoneTimeSuggestion bestPhoneSuggestion = findBestPhoneSuggestion();
+ if (bestPhoneSuggestion != null) {
+ final TimestampedValue<Long> newUtcTime = bestPhoneSuggestion.getUtcTime();
+ String cause = "Found good phone suggestion."
+ + ", bestPhoneSuggestion=" + bestPhoneSuggestion
+ + ", detectionReason=" + detectionReason;
+ setSystemClockIfRequired(ORIGIN_PHONE, newUtcTime, cause);
+ return;
+ }
- // 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);
- }
+ // There is no good phone suggestion, try network.
+ NetworkTimeSuggestion networkSuggestion = findLatestValidNetworkSuggestion();
+ if (networkSuggestion != null) {
+ final TimestampedValue<Long> newUtcTime = networkSuggestion.getUtcTime();
+ String cause = "Found good network suggestion."
+ + ", networkSuggestion=" + networkSuggestion
+ + ", detectionReason=" + detectionReason;
+ setSystemClockIfRequired(ORIGIN_NETWORK, newUtcTime, cause);
return;
}
- final TimestampedValue<Long> newUtcTime = bestPhoneSuggestion.getUtcTime();
- String cause = "Found good suggestion."
- + ", bestPhoneSuggestion=" + bestPhoneSuggestion
- + ", detectionReason=" + detectionReason;
- setSystemClockIfRequired(ORIGIN_PHONE, newUtcTime, cause);
+ if (DBG) {
+ Slog.d(LOG_TAG, "Could not determine time: No best phone or network suggestion."
+ + " detectionReason=" + detectionReason);
+ }
}
@GuardedBy("this")
@@ -342,37 +387,50 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
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.
+
+ // Validate first.
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. "
+ if (!validateSuggestionUtcTime(elapsedRealtimeMillis, utcTime)) {
+ Slog.w(LOG_TAG, "Existing suggestion found to be invalid "
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ ", timeSuggestion=" + timeSuggestion);
return PHONE_INVALID_SCORE;
}
- long ageMillis = elapsedRealtimeMillis - referenceTimeMillis;
+ // 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.
+ long ageMillis = elapsedRealtimeMillis - utcTime.getReferenceTimeMillis();
- // 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) {
+ // Turn the age into a discrete value: 0 <= bucketIndex < PHONE_BUCKET_COUNT.
+ int bucketIndex = (int) (ageMillis / PHONE_BUCKET_SIZE_MILLIS);
+ if (bucketIndex >= PHONE_BUCKET_COUNT) {
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;
}
+ /** Returns the latest, valid, network suggestion. Returns {@code null} if there isn't one. */
+ @GuardedBy("this")
+ @Nullable
+ private NetworkTimeSuggestion findLatestValidNetworkSuggestion() {
+ NetworkTimeSuggestion networkSuggestion = mLastNetworkSuggestion.get();
+ if (networkSuggestion == null) {
+ // No network suggestions received. This is normal if there's no connectivity.
+ return null;
+ }
+
+ TimestampedValue<Long> utcTime = networkSuggestion.getUtcTime();
+ long elapsedRealTimeMillis = mCallback.elapsedRealtimeMillis();
+ if (!validateSuggestionUtcTime(elapsedRealTimeMillis, utcTime)) {
+ // The latest suggestion is not valid, usually due to its age.
+ return null;
+ }
+
+ return networkSuggestion;
+ }
+
@GuardedBy("this")
private void setSystemClockIfRequired(
@Origin int origin, @NonNull TimestampedValue<Long> time, @NonNull String cause) {
@@ -409,7 +467,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
}
private static boolean isOriginAutomatic(@Origin int origin) {
- return origin == ORIGIN_PHONE;
+ return origin != ORIGIN_MANUAL;
}
@GuardedBy("this")
@@ -501,6 +559,16 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
}
/**
+ * Returns the latest valid network suggestion. Not intended for general use: it is used during
+ * tests to check strategy behavior.
+ */
+ @VisibleForTesting
+ @Nullable
+ public NetworkTimeSuggestion findLatestValidNetworkSuggestionForTests() {
+ return findLatestValidNetworkSuggestion();
+ }
+
+ /**
* A method used to inspect state during tests. Not intended for general use.
*/
@VisibleForTesting
@@ -508,4 +576,32 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
public synchronized PhoneTimeSuggestion getLatestPhoneSuggestion(int phoneId) {
return mSuggestionByPhoneId.get(phoneId);
}
+
+ /**
+ * A method used to inspect state during tests. Not intended for general use.
+ */
+ @VisibleForTesting
+ @Nullable
+ public NetworkTimeSuggestion getLatestNetworkSuggestion() {
+ return mLastNetworkSuggestion.get();
+ }
+
+ private static boolean validateSuggestionUtcTime(
+ long elapsedRealtimeMillis, TimestampedValue<Long> utcTime) {
+ long referenceTimeMillis = utcTime.getReferenceTimeMillis();
+ if (referenceTimeMillis > elapsedRealtimeMillis) {
+ // Future reference times are ignored. They imply the reference time was wrong, or the
+ // elapsed realtime clock used to derive it has gone backwards, neither of which are
+ // supportable situations.
+ return false;
+ }
+
+ // 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.
+ long ageMillis = elapsedRealtimeMillis - referenceTimeMillis;
+ return ageMillis <= MAX_UTC_TIME_AGE_MILLIS;
+ }
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 18ed51a6cd5e..5b58199aec4f 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -1814,8 +1814,8 @@ public final class TvInputManagerService extends SystemService {
}
@Override
- public ParcelFileDescriptor openDvbDevice(DvbDeviceInfo info, int device)
- throws RemoteException {
+ public ParcelFileDescriptor openDvbDevice(DvbDeviceInfo info,
+ @TvInputManager.DvbDeviceType int deviceType) throws RemoteException {
if (mContext.checkCallingPermission(android.Manifest.permission.DVB_DEVICE)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires DVB_DEVICE permission");
@@ -1852,7 +1852,7 @@ public final class TvInputManagerService extends SystemService {
final long identity = Binder.clearCallingIdentity();
try {
String deviceFileName;
- switch (device) {
+ switch (deviceType) {
case TvInputManager.DVB_DEVICE_DEMUX:
deviceFileName = String.format(dvbDeviceFound
? "/dev/dvb/adapter%d/demux%d" : "/dev/dvb%d.demux%d",
@@ -1869,14 +1869,14 @@ public final class TvInputManagerService extends SystemService {
info.getAdapterId(), info.getDeviceId());
break;
default:
- throw new IllegalArgumentException("Invalid DVB device: " + device);
+ throw new IllegalArgumentException("Invalid DVB device: " + deviceType);
}
try {
// The DVB frontend device only needs to be opened in read/write mode, which
// allows performing tuning operations. The DVB demux and DVR device are enough
// to be opened in read only mode.
return ParcelFileDescriptor.open(new File(deviceFileName),
- TvInputManager.DVB_DEVICE_FRONTEND == device
+ TvInputManager.DVB_DEVICE_FRONTEND == deviceType
? ParcelFileDescriptor.MODE_READ_WRITE
: ParcelFileDescriptor.MODE_READ_ONLY);
} catch (FileNotFoundException e) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 127b8e016d15..952a64cb2d7c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -206,6 +206,7 @@ import android.provider.ContactsContract.QuickContact;
import android.provider.ContactsInternal;
import android.provider.Settings;
import android.provider.Settings.Global;
+import android.provider.Telephony;
import android.security.IKeyChainAliasCallback;
import android.security.IKeyChainService;
import android.security.KeyChain;
@@ -246,6 +247,7 @@ import com.android.internal.telephony.SmsApplication;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
+import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.Preconditions;
import com.android.internal.util.StatLogger;
@@ -2061,6 +2063,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Binder.withCleanCallingIdentity(action);
}
+ final <T> T binderWithCleanCallingIdentity(@NonNull ThrowingSupplier<T> action) {
+ return Binder.withCleanCallingIdentity(action);
+ }
+
final int userHandleGetCallingUserId() {
return UserHandle.getUserId(binderGetCallingUid());
}
@@ -13936,23 +13942,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkNotNull(apnSetting, "ApnSetting is null in addOverrideApn");
enforceDeviceOwner(who);
- int operatedId = -1;
- Uri resultUri;
- final long id = mInjector.binderClearCallingIdentity();
- try {
- resultUri = mContext.getContentResolver().insert(DPC_URI, apnSetting.toContentValues());
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
- }
- if (resultUri != null) {
- try {
- operatedId = Integer.parseInt(resultUri.getLastPathSegment());
- } catch (NumberFormatException e) {
- Slog.e(LOG_TAG, "Failed to parse inserted override APN id.", e);
- }
+ TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+ if (tm != null) {
+ return mInjector.binderWithCleanCallingIdentity(
+ () -> tm.addDevicePolicyOverrideApn(mContext, apnSetting));
+ } else {
+ Log.w(LOG_TAG, "TelephonyManager is null when trying to add override apn");
+ return Telephony.Carriers.INVALID_APN_ID;
}
-
- return operatedId;
}
@Override
@@ -13968,13 +13965,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (apnId < 0) {
return false;
}
- final long id = mInjector.binderClearCallingIdentity();
- try {
- return mContext.getContentResolver().update(
- Uri.withAppendedPath(DPC_URI, Integer.toString(apnId)),
- apnSetting.toContentValues(), null, null) > 0;
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
+ TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+ if (tm != null) {
+ return mInjector.binderWithCleanCallingIdentity(
+ () -> tm.modifyDevicePolicyOverrideApn(mContext, apnId, apnSetting));
+ } else {
+ Log.w(LOG_TAG, "TelephonyManager is null when trying to modify override apn");
+ return false;
}
}
@@ -14016,28 +14013,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
private List<ApnSetting> getOverrideApnsUnchecked() {
- final Cursor cursor;
- final long id = mInjector.binderClearCallingIdentity();
- try {
- cursor = mContext.getContentResolver().query(DPC_URI, null, null, null, null);
- } finally {
- mInjector.binderRestoreCallingIdentity(id);
- }
-
- if (cursor == null) {
- return Collections.emptyList();
- }
- try {
- List<ApnSetting> apnList = new ArrayList<ApnSetting>();
- cursor.moveToPosition(-1);
- while (cursor.moveToNext()) {
- ApnSetting apn = ApnSetting.makeApnSetting(cursor);
- apnList.add(apn);
- }
- return apnList;
- } finally {
- cursor.close();
+ TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+ if (tm != null) {
+ return mInjector.binderWithCleanCallingIdentity(
+ () -> tm.getDevicePolicyOverrideApns(mContext));
}
+ Log.w(LOG_TAG, "TelephonyManager is null when trying to get override apns");
+ return Collections.emptyList();
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 1a67576c218f..960f670904d6 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -217,6 +217,8 @@ public class DpmMockContext extends MockContext {
return mMockSystemServices.wifiManager;
case Context.ACCOUNT_SERVICE:
return mMockSystemServices.accountManager;
+ case Context.TELEPHONY_SERVICE:
+ return mMockSystemServices.telephonyManager;
}
throw new UnsupportedOperationException();
}
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 72a7f508772b..71b568cc06c5 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -18,15 +18,18 @@ package com.android.server.timedetector;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -77,6 +80,22 @@ public class TimeDetectorServiceTest {
mHandlerThread.join();
}
+ @Test(expected = SecurityException.class)
+ public void testSuggestPhoneTime_withoutPermission() {
+ doThrow(new SecurityException("Mock"))
+ .when(mMockContext).enforceCallingPermission(anyString(), any());
+ PhoneTimeSuggestion phoneTimeSuggestion = createPhoneTimeSuggestion();
+
+ try {
+ mTimeDetectorService.suggestPhoneTime(phoneTimeSuggestion);
+ fail();
+ } finally {
+ verify(mMockContext).enforceCallingPermission(
+ eq(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE),
+ anyString());
+ }
+ }
+
@Test
public void testSuggestPhoneTime() throws Exception {
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
@@ -86,13 +105,29 @@ public class TimeDetectorServiceTest {
mTestHandler.assertTotalMessagesEnqueued(1);
verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.SET_TIME),
+ eq(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE),
anyString());
mTestHandler.waitForEmptyQueue();
mStubbedTimeDetectorStrategy.verifySuggestPhoneTimeCalled(phoneTimeSuggestion);
}
+ @Test(expected = SecurityException.class)
+ public void testSuggestManualTime_withoutPermission() {
+ doThrow(new SecurityException("Mock"))
+ .when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
+ ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion();
+
+ try {
+ mTimeDetectorService.suggestManualTime(manualTimeSuggestion);
+ fail();
+ } finally {
+ verify(mMockContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE),
+ anyString());
+ }
+ }
+
@Test
public void testSuggestManualTime() throws Exception {
doNothing().when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
@@ -102,13 +137,43 @@ public class TimeDetectorServiceTest {
mTestHandler.assertTotalMessagesEnqueued(1);
verify(mMockContext).enforceCallingOrSelfPermission(
- eq(android.Manifest.permission.SET_TIME),
+ eq(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE),
anyString());
mTestHandler.waitForEmptyQueue();
mStubbedTimeDetectorStrategy.verifySuggestManualTimeCalled(manualTimeSuggestion);
}
+ @Test(expected = SecurityException.class)
+ public void testSuggestNetworkTime_withoutPermission() {
+ doThrow(new SecurityException("Mock"))
+ .when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
+ NetworkTimeSuggestion NetworkTimeSuggestion = createNetworkTimeSuggestion();
+
+ try {
+ mTimeDetectorService.suggestNetworkTime(NetworkTimeSuggestion);
+ fail();
+ } finally {
+ verify(mMockContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.SET_TIME), anyString());
+ }
+ }
+
+ @Test
+ public void testSuggestNetworkTime() throws Exception {
+ doNothing().when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
+
+ NetworkTimeSuggestion NetworkTimeSuggestion = createNetworkTimeSuggestion();
+ mTimeDetectorService.suggestNetworkTime(NetworkTimeSuggestion);
+ mTestHandler.assertTotalMessagesEnqueued(1);
+
+ verify(mMockContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.SET_TIME), anyString());
+
+ mTestHandler.waitForEmptyQueue();
+ mStubbedTimeDetectorStrategy.verifySuggestNetworkTimeCalled(NetworkTimeSuggestion);
+ }
+
@Test
public void testDump() {
when(mMockContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP))
@@ -146,11 +211,17 @@ public class TimeDetectorServiceTest {
return new ManualTimeSuggestion(timeValue);
}
+ private static NetworkTimeSuggestion createNetworkTimeSuggestion() {
+ TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
+ return new NetworkTimeSuggestion(timeValue);
+ }
+
private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy {
// Call tracking.
private PhoneTimeSuggestion mLastPhoneSuggestion;
private ManualTimeSuggestion mLastManualSuggestion;
+ private NetworkTimeSuggestion mLastNetworkSuggestion;
private boolean mLastAutoTimeDetectionToggleCalled;
private boolean mDumpCalled;
@@ -171,6 +242,12 @@ public class TimeDetectorServiceTest {
}
@Override
+ public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) {
+ resetCallTracking();
+ mLastNetworkSuggestion = timeSuggestion;
+ }
+
+ @Override
public void handleAutoTimeDetectionChanged() {
resetCallTracking();
mLastAutoTimeDetectionToggleCalled = true;
@@ -185,6 +262,7 @@ public class TimeDetectorServiceTest {
void resetCallTracking() {
mLastPhoneSuggestion = null;
mLastManualSuggestion = null;
+ mLastNetworkSuggestion = null;
mLastAutoTimeDetectionToggleCalled = false;
mDumpCalled = false;
}
@@ -197,6 +275,10 @@ public class TimeDetectorServiceTest {
assertEquals(expectedSuggestion, mLastManualSuggestion);
}
+ public void verifySuggestNetworkTimeCalled(NetworkTimeSuggestion expectedSuggestion) {
+ assertEquals(expectedSuggestion, mLastNetworkSuggestion);
+ }
+
void verifyHandleAutoTimeDetectionToggleCalled() {
assertTrue(mLastAutoTimeDetectionToggleCalled);
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index 1aa3d8fe654b..ca6fd08092df 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
import android.icu.util.Calendar;
@@ -45,14 +46,16 @@ public class TimeDetectorStrategyImplTest {
private static final TimestampedValue<Long> ARBITRARY_CLOCK_INITIALIZATION_INFO =
new TimestampedValue<>(
123456789L /* realtimeClockMillis */,
- createUtcTime(1977, 1, 1, 12, 0, 0));
+ createUtcTime(2008, 5, 23, 12, 0, 0));
+ /**
+ * An arbitrary time, very different from the {@link #ARBITRARY_CLOCK_INITIALIZATION_INFO}
+ * time. Can be used as the basis for time suggestions.
+ */
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
@@ -67,15 +70,16 @@ public class TimeDetectorStrategyImplTest {
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()
+ .simulatePhoneTimeSuggestion(timeSuggestion);
- mScript.simulateTimePassing(clockIncrement)
- .simulatePhoneTimeSuggestion(timeSuggestion)
- .verifySystemClockWasSetAndResetCallTracking(
- expectedSystemClockMillis, true /* expectNetworkBroadcast */)
+ long expectedSystemClockMillis =
+ mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime());
+ mScript.verifySystemClockWasSetAndResetCallTracking(
+ expectedSystemClockMillis, true /* expectNetworkBroadcast */)
.assertLatestPhoneSuggestion(phoneId, timeSuggestion);
}
@@ -94,26 +98,24 @@ public class TimeDetectorStrategyImplTest {
@Test
public void testSuggestPhoneTime_systemClockThreshold() {
- int systemClockUpdateThresholdMillis = 1000;
+ final int systemClockUpdateThresholdMillis = 1000;
+ final int clockIncrementMillis = 100;
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();
+ mScript.generatePhoneTimeSuggestion(phoneId, ARBITRARY_TEST_TIME_MILLIS);
// Increment the the device clocks to simulate the passage of time.
- mScript.simulateTimePassing(clockIncrement);
+ mScript.simulateTimePassing(clockIncrementMillis);
long expectedSystemClockMillis1 =
- TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
+ mScript.calculateTimeInMillisForNow(timeSuggestion1.getUtcTime());
mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(
@@ -127,7 +129,7 @@ public class TimeDetectorStrategyImplTest {
int underThresholdMillis = systemClockUpdateThresholdMillis - 1;
PhoneTimeSuggestion timeSuggestion2 = mScript.generatePhoneTimeSuggestion(
phoneId, mScript.peekSystemClockMillis() + underThresholdMillis);
- mScript.simulateTimePassing(clockIncrement)
+ mScript.simulateTimePassing(clockIncrementMillis)
.simulatePhoneTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestPhoneSuggestion(phoneId, timeSuggestion2);
@@ -138,11 +140,10 @@ public class TimeDetectorStrategyImplTest {
PhoneTimeSuggestion timeSuggestion3 = mScript.generatePhoneTimeSuggestion(
phoneId,
mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis);
- mScript.simulateTimePassing(clockIncrement);
+ mScript.simulateTimePassing(clockIncrementMillis);
long expectedSystemClockMillis3 =
- TimeDetectorStrategy.getTimeAt(timeSuggestion3.getUtcTime(),
- mScript.peekElapsedRealtimeMillis());
+ mScript.calculateTimeInMillisForNow(timeSuggestion3.getUtcTime());
mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
.verifySystemClockWasSetAndResetCallTracking(
@@ -162,17 +163,16 @@ public class TimeDetectorStrategyImplTest {
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;
+ long phone2TimeMillis = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(1).toMillis();
// Make a suggestion with phone2Id.
{
PhoneTimeSuggestion phone2TimeSuggestion =
mScript.generatePhoneTimeSuggestion(phone2Id, phone2TimeMillis);
- mScript.simulateTimePassing(clockIncrement);
+ mScript.simulateTimePassing();
- long expectedSystemClockMillis = phone2TimeMillis + clockIncrement;
+ long expectedSystemClockMillis =
+ mScript.calculateTimeInMillisForNow(phone2TimeSuggestion.getUtcTime());
mScript.simulatePhoneTimeSuggestion(phone2TimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
@@ -181,15 +181,16 @@ public class TimeDetectorStrategyImplTest {
.assertLatestPhoneSuggestion(phone2Id, phone2TimeSuggestion);
}
- mScript.simulateTimePassing(clockIncrement);
+ mScript.simulateTimePassing();
// Now make a different suggestion with phone1Id.
{
PhoneTimeSuggestion phone1TimeSuggestion =
mScript.generatePhoneTimeSuggestion(phone1Id, phone1TimeMillis);
- mScript.simulateTimePassing(clockIncrement);
+ mScript.simulateTimePassing();
- long expectedSystemClockMillis = phone1TimeMillis + clockIncrement;
+ long expectedSystemClockMillis =
+ mScript.calculateTimeInMillisForNow(phone1TimeSuggestion.getUtcTime());
mScript.simulatePhoneTimeSuggestion(phone1TimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
@@ -198,14 +199,14 @@ public class TimeDetectorStrategyImplTest {
}
- mScript.simulateTimePassing(clockIncrement);
+ mScript.simulateTimePassing();
// 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.simulateTimePassing();
mScript.simulatePhoneTimeSuggestion(phone2TimeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking()
@@ -220,9 +221,10 @@ public class TimeDetectorStrategyImplTest {
{
PhoneTimeSuggestion phone2TimeSuggestion =
mScript.generatePhoneTimeSuggestion(phone2Id, phone2TimeMillis);
- mScript.simulateTimePassing(clockIncrement);
+ mScript.simulateTimePassing();
- long expectedSystemClockMillis = phone2TimeMillis + clockIncrement;
+ long expectedSystemClockMillis =
+ mScript.calculateTimeInMillisForNow(phone2TimeSuggestion.getUtcTime());
mScript.simulatePhoneTimeSuggestion(phone2TimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
@@ -239,7 +241,7 @@ public class TimeDetectorStrategyImplTest {
int phoneId = ARBITRARY_PHONE_ID;
PhoneTimeSuggestion timeSuggestion =
mScript.generatePhoneTimeSuggestion(phoneId, ARBITRARY_TEST_TIME_MILLIS);
- mScript.simulateTimePassing(1000)
+ mScript.simulateTimePassing()
.simulatePhoneTimeSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestPhoneSuggestion(phoneId, timeSuggestion);
@@ -260,9 +262,8 @@ public class TimeDetectorStrategyImplTest {
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.simulateTimePassing();
+ long expectedSystemClockMillis1 = mScript.calculateTimeInMillisForNow(utcTime1);
mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
.verifySystemClockWasSetAndResetCallTracking(
expectedSystemClockMillis1, true /* expectNetworkBroadcast */)
@@ -299,8 +300,7 @@ public class TimeDetectorStrategyImplTest {
long validReferenceTimeMillis = utcTime1.getReferenceTimeMillis() + 100;
TimestampedValue<Long> utcTime4 = new TimestampedValue<>(
validReferenceTimeMillis, validUtcTimeMillis);
- long expectedSystemClockMillis4 =
- TimeDetectorStrategy.getTimeAt(utcTime4, mScript.peekElapsedRealtimeMillis());
+ long expectedSystemClockMillis4 = mScript.calculateTimeInMillisForNow(utcTime4);
PhoneTimeSuggestion timeSuggestion4 =
createPhoneTimeSuggestion(phoneId, utcTime4);
mScript.simulatePhoneTimeSuggestion(timeSuggestion4)
@@ -335,8 +335,7 @@ public class TimeDetectorStrategyImplTest {
// Simulate more time passing.
mScript.simulateTimePassing(clockIncrementMillis);
- long expectedSystemClockMillis1 =
- TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
+ long expectedSystemClockMillis1 = mScript.calculateTimeInMillisForNow(utcTime1);
// Turn on auto time detection.
mScript.simulateAutoTimeDetectionToggle()
@@ -357,8 +356,8 @@ public class TimeDetectorStrategyImplTest {
// Simulate more time passing.
mScript.simulateTimePassing(clockIncrementMillis);
- long expectedSystemClockMillis2 = TimeDetectorStrategy.getTimeAt(
- timeSuggestion2.getUtcTime(), mScript.peekElapsedRealtimeMillis());
+ long expectedSystemClockMillis2 =
+ mScript.calculateTimeInMillisForNow(timeSuggestion2.getUtcTime());
// The new time, though valid, should not be set in the system clock because auto time is
// disabled.
@@ -382,19 +381,21 @@ public class TimeDetectorStrategyImplTest {
long testTimeMillis = ARBITRARY_TEST_TIME_MILLIS;
PhoneTimeSuggestion phoneSuggestion =
mScript.generatePhoneTimeSuggestion(phoneId, testTimeMillis);
- int clockIncrementMillis = 1000;
- mScript.simulateTimePassing(clockIncrementMillis)
- .simulatePhoneTimeSuggestion(phoneSuggestion)
+ mScript.simulateTimePassing();
+
+ long expectedSystemClockMillis =
+ mScript.calculateTimeInMillisForNow(phoneSuggestion.getUtcTime());
+ mScript.simulatePhoneTimeSuggestion(phoneSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
- testTimeMillis + clockIncrementMillis, true /* expectedNetworkBroadcast */)
+ expectedSystemClockMillis, 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);
+ mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_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.
@@ -407,13 +408,14 @@ public class TimeDetectorStrategyImplTest {
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;
+ ManualTimeSuggestion timeSuggestion =
+ mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS);
- mScript.simulateTimePassing(clockIncrement)
- .simulateManualTimeSuggestion(timeSuggestion)
+ mScript.simulateTimePassing();
+
+ long expectedSystemClockMillis =
+ mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime());
+ mScript.simulateManualTimeSuggestion(timeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
expectedSystemClockMillis, false /* expectNetworkBroadcast */);
}
@@ -430,21 +432,19 @@ public class TimeDetectorStrategyImplTest {
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.simulateTimePassing();
+ long expectedAutoClockMillis =
+ mScript.calculateTimeInMillisForNow(phoneTimeSuggestion.getUtcTime());
mScript.simulatePhoneTimeSuggestion(phoneTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
expectedAutoClockMillis, true /* expectNetworkBroadcast */)
.assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion);
// Simulate the passage of time.
- mScript.simulateTimePassing(clockIncrement);
- expectedAutoClockMillis += clockIncrement;
+ mScript.simulateTimePassing();
// Switch to manual.
mScript.simulateAutoTimeDetectionToggle()
@@ -452,26 +452,29 @@ public class TimeDetectorStrategyImplTest {
.assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion);
// Simulate the passage of time.
- mScript.simulateTimePassing(clockIncrement);
- expectedAutoClockMillis += clockIncrement;
+ mScript.simulateTimePassing();
// Simulate a manual suggestion 1 day different from the auto suggestion.
- long manualTimeMillis = testTimeMillis + ONE_DAY_MILLIS;
- long expectedManualClockMillis = manualTimeMillis;
+ long manualTimeMillis = testTimeMillis + Duration.ofDays(1).toMillis();
ManualTimeSuggestion manualTimeSuggestion =
mScript.generateManualTimeSuggestion(manualTimeMillis);
+ mScript.simulateTimePassing();
+
+ long expectedManualClockMillis =
+ mScript.calculateTimeInMillisForNow(manualTimeSuggestion.getUtcTime());
mScript.simulateManualTimeSuggestion(manualTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(
expectedManualClockMillis, false /* expectNetworkBroadcast */)
.assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion);
// Simulate the passage of time.
- mScript.simulateTimePassing(clockIncrement);
- expectedAutoClockMillis += clockIncrement;
+ mScript.simulateTimePassing();
// Switch back to auto.
mScript.simulateAutoTimeDetectionToggle();
+ expectedAutoClockMillis =
+ mScript.calculateTimeInMillisForNow(phoneTimeSuggestion.getUtcTime());
mScript.verifySystemClockWasSetAndResetCallTracking(
expectedAutoClockMillis, true /* expectNetworkBroadcast */)
.assertLatestPhoneSuggestion(phoneId, phoneTimeSuggestion);
@@ -492,13 +495,143 @@ public class TimeDetectorStrategyImplTest {
ManualTimeSuggestion timeSuggestion =
mScript.generateManualTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS);
- final int clockIncrement = 1000;
- mScript.simulateTimePassing(clockIncrement)
+ mScript.simulateTimePassing()
.simulateManualTimeSuggestion(timeSuggestion)
.verifySystemClockWasNotSetAndResetCallTracking();
}
+ @Test
+ public void testSuggestNetworkTime_autoTimeEnabled() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true);
+
+ NetworkTimeSuggestion timeSuggestion =
+ mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS);
+
+ mScript.simulateTimePassing();
+
+ long expectedSystemClockMillis =
+ mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime());
+ mScript.simulateNetworkTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedSystemClockMillis, false /* expectNetworkBroadcast */);
+ }
+
+ @Test
+ public void testSuggestNetworkTime_autoTimeDisabled() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(false);
+
+ NetworkTimeSuggestion timeSuggestion =
+ mScript.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME_MILLIS);
+
+ mScript.simulateTimePassing()
+ .simulateNetworkTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+ }
+
+ @Test
+ public void testSuggestNetworkTime_phoneSuggestionsBeatNetworkSuggestions() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true);
+
+ // Three obviously different times that could not be mistaken for each other.
+ long networkTimeMillis1 = ARBITRARY_TEST_TIME_MILLIS;
+ long networkTimeMillis2 = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(30).toMillis();
+ long phoneTimeMillis = ARBITRARY_TEST_TIME_MILLIS + Duration.ofDays(60).toMillis();
+ // A small increment used to simulate the passage of time, but not enough to interfere with
+ // macro-level time changes associated with suggestion age.
+ final long smallTimeIncrementMillis = 101;
+
+ // A network suggestion is made. It should be used because there is no phone suggestion.
+ NetworkTimeSuggestion networkTimeSuggestion1 =
+ mScript.generateNetworkTimeSuggestion(networkTimeMillis1);
+ mScript.simulateTimePassing(smallTimeIncrementMillis)
+ .simulateNetworkTimeSuggestion(networkTimeSuggestion1)
+ .verifySystemClockWasSetAndResetCallTracking(
+ mScript.calculateTimeInMillisForNow(networkTimeSuggestion1.getUtcTime()),
+ false /* expectNetworkBroadcast */);
+
+ // Check internal state.
+ mScript.assertLatestPhoneSuggestion(ARBITRARY_PHONE_ID, null)
+ .assertLatestNetworkSuggestion(networkTimeSuggestion1);
+ assertEquals(networkTimeSuggestion1, mScript.peekLatestValidNetworkSuggestion());
+ assertNull(mScript.peekBestPhoneSuggestion());
+
+ // Simulate a little time passing.
+ mScript.simulateTimePassing(smallTimeIncrementMillis)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Now a phone suggestion is made. Phone suggestions are prioritized over network
+ // suggestions so it should "win".
+ PhoneTimeSuggestion phoneTimeSuggestion =
+ mScript.generatePhoneTimeSuggestion(ARBITRARY_PHONE_ID, phoneTimeMillis);
+ mScript.simulateTimePassing(smallTimeIncrementMillis)
+ .simulatePhoneTimeSuggestion(phoneTimeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(
+ mScript.calculateTimeInMillisForNow(phoneTimeSuggestion.getUtcTime()),
+ true /* expectNetworkBroadcast */);
+
+ // Check internal state.
+ mScript.assertLatestPhoneSuggestion(ARBITRARY_PHONE_ID, phoneTimeSuggestion)
+ .assertLatestNetworkSuggestion(networkTimeSuggestion1);
+ assertEquals(networkTimeSuggestion1, mScript.peekLatestValidNetworkSuggestion());
+ assertEquals(phoneTimeSuggestion, mScript.peekBestPhoneSuggestion());
+
+ // Simulate some significant time passing: half the time allowed before a time signal
+ // becomes "too old to use".
+ mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS / 2)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Now another network suggestion is made. Phone suggestions are prioritized over network
+ // suggestions so the latest phone suggestion should still "win".
+ NetworkTimeSuggestion networkTimeSuggestion2 =
+ mScript.generateNetworkTimeSuggestion(networkTimeMillis2);
+ mScript.simulateTimePassing(smallTimeIncrementMillis)
+ .simulateNetworkTimeSuggestion(networkTimeSuggestion2)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Check internal state.
+ mScript.assertLatestPhoneSuggestion(ARBITRARY_PHONE_ID, phoneTimeSuggestion)
+ .assertLatestNetworkSuggestion(networkTimeSuggestion2);
+ assertEquals(networkTimeSuggestion2, mScript.peekLatestValidNetworkSuggestion());
+ assertEquals(phoneTimeSuggestion, mScript.peekBestPhoneSuggestion());
+
+ // Simulate some significant time passing: half the time allowed before a time signal
+ // becomes "too old to use". This should mean that phoneTimeSuggestion is now too old to be
+ // used but networkTimeSuggestion2 is not.
+ mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS / 2);
+
+ // NOTE: The TimeDetectorStrategyImpl doesn't set an alarm for the point when the last
+ // suggestion it used becomes too old: it requires a new suggestion or an auto-time toggle
+ // to re-run the detection logic. This may change in future but until then we rely on a
+ // steady stream of suggestions to re-evaluate.
+ mScript.verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Check internal state.
+ mScript.assertLatestPhoneSuggestion(ARBITRARY_PHONE_ID, phoneTimeSuggestion)
+ .assertLatestNetworkSuggestion(networkTimeSuggestion2);
+ assertEquals(networkTimeSuggestion2, mScript.peekLatestValidNetworkSuggestion());
+ assertNull(mScript.peekBestPhoneSuggestion());
+
+ // Toggle auto-time off and on to force the detection logic to run.
+ mScript.simulateAutoTimeDetectionToggle()
+ .simulateTimePassing(smallTimeIncrementMillis)
+ .simulateAutoTimeDetectionToggle();
+
+ // Verify the latest network time now wins.
+ mScript.verifySystemClockWasSetAndResetCallTracking(
+ mScript.calculateTimeInMillisForNow(networkTimeSuggestion2.getUtcTime()),
+ false /* expectNetworkTimeBroadcast */);
+
+ // Check internal state.
+ mScript.assertLatestPhoneSuggestion(ARBITRARY_PHONE_ID, phoneTimeSuggestion)
+ .assertLatestNetworkSuggestion(networkTimeSuggestion2);
+ assertEquals(networkTimeSuggestion2, mScript.peekLatestValidNetworkSuggestion());
+ assertNull(mScript.peekBestPhoneSuggestion());
+ }
+
/**
* A fake implementation of TimeDetectorStrategy.Callback. Besides tracking changes and behaving
* like the real thing should, it also asserts preconditions.
@@ -674,6 +807,11 @@ public class TimeDetectorStrategyImplTest {
return this;
}
+ Script simulateNetworkTimeSuggestion(NetworkTimeSuggestion timeSuggestion) {
+ mTimeDetectorStrategy.suggestNetworkTime(timeSuggestion);
+ return this;
+ }
+
Script simulateAutoTimeDetectionToggle() {
mFakeCallback.simulateAutoTimeZoneDetectionToggle();
mTimeDetectorStrategy.handleAutoTimeDetectionChanged();
@@ -685,6 +823,13 @@ public class TimeDetectorStrategyImplTest {
return this;
}
+ /**
+ * Simulates time passing by an arbitrary (but relatively small) amount.
+ */
+ Script simulateTimePassing() {
+ return simulateTimePassing(999);
+ }
+
Script verifySystemClockWasNotSetAndResetCallTracking() {
mFakeCallback.verifySystemClockNotSet();
mFakeCallback.verifyIntentWasNotBroadcast();
@@ -711,14 +856,30 @@ public class TimeDetectorStrategyImplTest {
}
/**
+ * White box test info: Asserts the latest network suggestion is as expected.
+ */
+ Script assertLatestNetworkSuggestion(NetworkTimeSuggestion expected) {
+ assertEquals(expected, mTimeDetectorStrategy.getLatestNetworkSuggestion());
+ return this;
+ }
+
+ /**
* White box test info: Returns the phone suggestion that would be used, if any, given the
- * current elapsed real time clock.
+ * current elapsed real time clock and regardless of origin prioritization.
*/
PhoneTimeSuggestion peekBestPhoneSuggestion() {
return mTimeDetectorStrategy.findBestPhoneSuggestionForTests();
}
/**
+ * White box test info: Returns the network suggestion that would be used, if any, given the
+ * current elapsed real time clock and regardless of origin prioritization.
+ */
+ NetworkTimeSuggestion peekLatestValidNetworkSuggestion() {
+ return mTimeDetectorStrategy.findLatestValidNetworkSuggestionForTests();
+ }
+
+ /**
* Generates a ManualTimeSuggestion using the current elapsed realtime clock for the
* reference time.
*/
@@ -739,6 +900,24 @@ public class TimeDetectorStrategyImplTest {
}
return createPhoneTimeSuggestion(phoneId, time);
}
+
+ /**
+ * Generates a NetworkTimeSuggestion using the current elapsed realtime clock for the
+ * reference time.
+ */
+ NetworkTimeSuggestion generateNetworkTimeSuggestion(long timeMillis) {
+ TimestampedValue<Long> utcTime =
+ new TimestampedValue<>(mFakeCallback.peekElapsedRealtimeMillis(), timeMillis);
+ return new NetworkTimeSuggestion(utcTime);
+ }
+
+ /**
+ * Calculates what the supplied time would be when adjusted for the movement of the fake
+ * elapsed realtime clock.
+ */
+ long calculateTimeInMillisForNow(TimestampedValue<Long> utcTime) {
+ return TimeDetectorStrategy.getTimeAt(utcTime, peekElapsedRealtimeMillis());
+ }
}
private static PhoneTimeSuggestion createPhoneTimeSuggestion(int phoneId,
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 0becaf237a73..8808339b1664 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -502,51 +502,116 @@ public abstract class Connection extends Conferenceable {
//**********************************************************************************************
/**
- * Define IMS Audio Codec
+ * Indicates that the audio codec is currently not specified or is unknown.
*/
- // Current audio codec is NONE
public static final int AUDIO_CODEC_NONE = ImsStreamMediaProfile.AUDIO_QUALITY_NONE; // 0
- // Current audio codec is AMR
+ /**
+ * Adaptive Multi-rate audio codec.
+ */
public static final int AUDIO_CODEC_AMR = ImsStreamMediaProfile.AUDIO_QUALITY_AMR; // 1
- // Current audio codec is AMR_WB
+ /**
+ * Adaptive Multi-rate wideband audio codec.
+ */
public static final int AUDIO_CODEC_AMR_WB = ImsStreamMediaProfile.AUDIO_QUALITY_AMR_WB; // 2
- // Current audio codec is QCELP13K
+ /**
+ * Qualcomm code-excited linear prediction 13 kilobit audio codec.
+ */
public static final int AUDIO_CODEC_QCELP13K = ImsStreamMediaProfile.AUDIO_QUALITY_QCELP13K; //3
- // Current audio codec is EVRC
+ /**
+ * Enhanced Variable Rate Codec. See 3GPP2 C.S0014-A.
+ */
public static final int AUDIO_CODEC_EVRC = ImsStreamMediaProfile.AUDIO_QUALITY_EVRC; // 4
- // Current audio codec is EVRC_B
+ /**
+ * Enhanced Variable Rate Codec B. Commonly used on CDMA networks.
+ */
public static final int AUDIO_CODEC_EVRC_B = ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_B; // 5
- // Current audio codec is EVRC_WB
+ /**
+ * Enhanced Variable Rate Wideband Codec. See RFC5188.
+ */
public static final int AUDIO_CODEC_EVRC_WB = ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_WB; // 6
- // Current audio codec is EVRC_NW
+ /**
+ * Enhanced Variable Rate Narrowband-Wideband Codec.
+ */
public static final int AUDIO_CODEC_EVRC_NW = ImsStreamMediaProfile.AUDIO_QUALITY_EVRC_NW; // 7
- // Current audio codec is GSM_EFR
+ /**
+ * GSM Enhanced Full-Rate audio codec, also known as GSM-EFR, GSM 06.60, or simply EFR.
+ */
public static final int AUDIO_CODEC_GSM_EFR = ImsStreamMediaProfile.AUDIO_QUALITY_GSM_EFR; // 8
- // Current audio codec is GSM_FR
+ /**
+ * GSM Full-Rate audio codec, also known as GSM-FR, GSM 06.10, GSM, or simply FR.
+ */
public static final int AUDIO_CODEC_GSM_FR = ImsStreamMediaProfile.AUDIO_QUALITY_GSM_FR; // 9
- // Current audio codec is GSM_HR
+ /**
+ * GSM Half Rate audio codec.
+ */
public static final int AUDIO_CODEC_GSM_HR = ImsStreamMediaProfile.AUDIO_QUALITY_GSM_HR; // 10
- // Current audio codec is G711U
+ /**
+ * ITU-T G711U audio codec.
+ */
public static final int AUDIO_CODEC_G711U = ImsStreamMediaProfile.AUDIO_QUALITY_G711U; // 11
- // Current audio codec is G723
+ /**
+ * ITU-T G723 audio codec.
+ */
public static final int AUDIO_CODEC_G723 = ImsStreamMediaProfile.AUDIO_QUALITY_G723; // 12
- // Current audio codec is G711A
+ /**
+ * ITU-T G711A audio codec.
+ */
public static final int AUDIO_CODEC_G711A = ImsStreamMediaProfile.AUDIO_QUALITY_G711A; // 13
- // Current audio codec is G722
+ /**
+ * ITU-T G722 audio codec.
+ */
public static final int AUDIO_CODEC_G722 = ImsStreamMediaProfile.AUDIO_QUALITY_G722; // 14
- // Current audio codec is G711AB
+ /**
+ * ITU-T G711AB audio codec.
+ */
public static final int AUDIO_CODEC_G711AB = ImsStreamMediaProfile.AUDIO_QUALITY_G711AB; // 15
- // Current audio codec is G729
+ /**
+ * ITU-T G729 audio codec.
+ */
public static final int AUDIO_CODEC_G729 = ImsStreamMediaProfile.AUDIO_QUALITY_G729; // 16
- // Current audio codec is EVS_NB
+ /**
+ * Enhanced Voice Services Narrowband audio codec. See 3GPP TS 26.441.
+ */
public static final int AUDIO_CODEC_EVS_NB = ImsStreamMediaProfile.AUDIO_QUALITY_EVS_NB; // 17
- // Current audio codec is EVS_WB
+ /**
+ * Enhanced Voice Services Wideband audio codec. See 3GPP TS 26.441.
+ */
public static final int AUDIO_CODEC_EVS_WB = ImsStreamMediaProfile.AUDIO_QUALITY_EVS_WB; // 18
- // Current audio codec is EVS_SWB
+ /**
+ * Enhanced Voice Services Super-Wideband audio codec. See 3GPP TS 26.441.
+ */
public static final int AUDIO_CODEC_EVS_SWB = ImsStreamMediaProfile.AUDIO_QUALITY_EVS_SWB; // 19
- // Current audio codec is EVS_FB
+ /**
+ * Enhanced Voice Services Fullband audio codec. See 3GPP TS 26.441.
+ */
public static final int AUDIO_CODEC_EVS_FB = ImsStreamMediaProfile.AUDIO_QUALITY_EVS_FB; // 20
+ /**@hide*/
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "AUDIO_CODEC_", value = {
+ AUDIO_CODEC_NONE,
+ AUDIO_CODEC_AMR,
+ AUDIO_CODEC_AMR_WB,
+ AUDIO_CODEC_QCELP13K,
+ AUDIO_CODEC_EVRC,
+ AUDIO_CODEC_EVRC_B,
+ AUDIO_CODEC_EVRC_WB,
+ AUDIO_CODEC_EVRC_NW,
+ AUDIO_CODEC_GSM_EFR,
+ AUDIO_CODEC_GSM_FR,
+ AUDIO_CODEC_GSM_HR,
+ AUDIO_CODEC_G711U,
+ AUDIO_CODEC_G723,
+ AUDIO_CODEC_G711A,
+ AUDIO_CODEC_G722,
+ AUDIO_CODEC_G711AB,
+ AUDIO_CODEC_G729,
+ AUDIO_CODEC_EVS_NB,
+ AUDIO_CODEC_EVS_SWB,
+ AUDIO_CODEC_EVS_FB
+ })
+ public @interface AudioCodec {}
+
/**
* Connection extra key used to store the last forwarded number associated with the current
* connection. Used to communicate to the user interface that the connection was forwarded via
@@ -640,10 +705,10 @@ public abstract class Connection extends Conferenceable {
"android.telecom.extra.IS_RTT_AUDIO_PRESENT";
/**
- * The audio codec in use for the current {@link Connection}, if known. Valid values include
- * {@link #AUDIO_CODEC_AMR_WB} and {@link #AUDIO_CODEC_EVS_WB}.
+ * The audio codec in use for the current {@link Connection}, if known. Examples of valid
+ * values include {@link #AUDIO_CODEC_AMR_WB} and {@link #AUDIO_CODEC_EVS_WB}.
*/
- public static final String EXTRA_AUDIO_CODEC =
+ public static final @AudioCodec String EXTRA_AUDIO_CODEC =
"android.telecom.extra.AUDIO_CODEC";
/**
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index df668ea2313d..07dfcf09b1c5 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -44,6 +44,7 @@ import android.telephony.Rlog;
import android.telephony.TelephonyManager;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -67,10 +68,10 @@ import java.util.function.Consumer;
*/
public final class SmsApplication {
static final String LOG_TAG = "SmsApplication";
- private static final String PHONE_PACKAGE_NAME = "com.android.phone";
- private static final String BLUETOOTH_PACKAGE_NAME = "com.android.bluetooth";
- private static final String MMS_SERVICE_PACKAGE_NAME = "com.android.mms.service";
- private static final String TELEPHONY_PROVIDER_PACKAGE_NAME = "com.android.providers.telephony";
+ public static final String PHONE_PACKAGE_NAME = "com.android.phone";
+ public static final String BLUETOOTH_PACKAGE_NAME = "com.android.bluetooth";
+ public static final String MMS_SERVICE_PACKAGE_NAME = "com.android.mms.service";
+ public static final String TELEPHONY_PROVIDER_PACKAGE_NAME = "com.android.providers.telephony";
private static final String SCHEME_SMS = "sms";
private static final String SCHEME_SMSTO = "smsto";
@@ -79,13 +80,13 @@ public final class SmsApplication {
private static final boolean DEBUG = false;
private static final boolean DEBUG_MULTIUSER = false;
- private static final int[] DEFAULT_APP_EXCLUSIVE_APPOPS = {
- AppOpsManager.OP_READ_SMS,
- AppOpsManager.OP_WRITE_SMS,
- AppOpsManager.OP_RECEIVE_SMS,
- AppOpsManager.OP_RECEIVE_WAP_PUSH,
- AppOpsManager.OP_SEND_SMS,
- AppOpsManager.OP_READ_CELL_BROADCASTS
+ private static final String[] DEFAULT_APP_EXCLUSIVE_APPOPS = {
+ AppOpsManager.OPSTR_READ_SMS,
+ AppOpsManager.OPSTR_WRITE_SMS,
+ AppOpsManager.OPSTR_RECEIVE_SMS,
+ AppOpsManager.OPSTR_RECEIVE_WAP_PUSH,
+ AppOpsManager.OPSTR_SEND_SMS,
+ AppOpsManager.OPSTR_READ_CELL_BROADCASTS
};
private static SmsPackageMonitor sSmsPackageMonitor = null;
@@ -501,7 +502,7 @@ public final class SmsApplication {
// If we found a package, make sure AppOps permissions are set up correctly
if (applicationData != null) {
- // We can only call checkOp if we are privileged (updateIfNeeded) or if the app we
+ // We can only call unsafeCheckOp if we are privileged (updateIfNeeded) or if the app we
// are checking is for our current uid. Doing this check from the unprivileged current
// SMS app allows us to tell the current SMS app that it is not in a good state and
// needs to ask to be the current SMS app again to work properly.
@@ -555,23 +556,23 @@ public final class SmsApplication {
// apps, all of them should be able to write to telephony provider.
// This is to allow the proxy package permission check in telephony provider
// to pass.
- for (int appop : DEFAULT_APP_EXCLUSIVE_APPOPS) {
- appOps.setUidMode(appop, Process.PHONE_UID, AppOpsManager.MODE_ALLOWED);
+ for (String opStr : DEFAULT_APP_EXCLUSIVE_APPOPS) {
+ appOps.setUidMode(opStr, Process.PHONE_UID, AppOpsManager.MODE_ALLOWED);
}
}
private static boolean tryFixExclusiveSmsAppops(Context context,
SmsApplicationData applicationData, boolean updateIfNeeded) {
AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
- for (int appOp : DEFAULT_APP_EXCLUSIVE_APPOPS) {
- int mode = appOps.checkOp(appOp, applicationData.mUid,
+ for (String opStr : DEFAULT_APP_EXCLUSIVE_APPOPS) {
+ int mode = appOps.unsafeCheckOp(opStr, applicationData.mUid,
applicationData.mPackageName);
if (mode != AppOpsManager.MODE_ALLOWED) {
Rlog.e(LOG_TAG, applicationData.mPackageName + " lost "
- + AppOpsManager.modeToName(appOp) + ": "
+ + opStr + ": "
+ (updateIfNeeded ? " (fixing)" : " (no permission to fix)"));
if (updateIfNeeded) {
- appOps.setUidMode(appOp, applicationData.mUid, AppOpsManager.MODE_ALLOWED);
+ appOps.setUidMode(opStr, applicationData.mUid, AppOpsManager.MODE_ALLOWED);
} else {
return false;
}
@@ -757,7 +758,7 @@ public final class SmsApplication {
}
try {
PackageInfo info = packageManager.getPackageInfo(packageName, 0);
- int mode = appOps.checkOp(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid,
+ int mode = appOps.unsafeCheckOp(AppOpsManager.OPSTR_WRITE_SMS, info.applicationInfo.uid,
packageName);
if (mode != AppOpsManager.MODE_ALLOWED) {
Rlog.w(LOG_TAG, packageName + " does not have OP_WRITE_SMS: (fixing)");
@@ -773,8 +774,8 @@ public final class SmsApplication {
private static void setExclusiveAppops(String pkg, AppOpsManager appOpsManager, int uid,
int mode) {
- for (int appop : DEFAULT_APP_EXCLUSIVE_APPOPS) {
- appOpsManager.setUidMode(appop, uid, mode);
+ for (String opStr : DEFAULT_APP_EXCLUSIVE_APPOPS) {
+ appOpsManager.setUidMode(opStr, uid, mode);
}
}
@@ -899,6 +900,7 @@ public final class SmsApplication {
* @param userId target user ID.
* @return component name of the app and class to deliver SMS messages to
*/
+ @VisibleForTesting
public static ComponentName getDefaultSmsApplicationAsUser(Context context,
boolean updateIfNeeded, int userId) {
final long token = Binder.clearCallingIdentity();
diff --git a/telephony/common/com/google/android/mms/pdu/PduPersister.java b/telephony/common/com/google/android/mms/pdu/PduPersister.java
index b237705274da..8efca0ea3909 100755
--- a/telephony/common/com/google/android/mms/pdu/PduPersister.java
+++ b/telephony/common/com/google/android/mms/pdu/PduPersister.java
@@ -34,6 +34,7 @@ import android.provider.Telephony.MmsSms;
import android.provider.Telephony.MmsSms.PendingMessages;
import android.provider.Telephony.Threads;
import android.telephony.PhoneNumberUtils;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -1448,9 +1449,9 @@ public class PduPersister {
final Set<String> myPhoneNumbers = new HashSet<String>();
if (excludeMyNumber) {
// Build a list of my phone numbers from the various sims.
- for (int subid : subscriptionManager.getActiveSubscriptionIdList()) {
+ for (SubscriptionInfo subInfo : subscriptionManager.getActiveSubscriptionInfoList()) {
final String myNumber = mContext.getSystemService(TelephonyManager.class).
- createForSubscriptionId(subid).getLine1Number();
+ createForSubscriptionId(subInfo.getSubscriptionId()).getLine1Number();
if (myNumber != null) {
myPhoneNumbers.add(myNumber);
}
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index 9aafc1be5831..aac56c08bdc4 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -332,17 +332,16 @@ public class SignalStrength implements Parcelable {
/**
* {@link Parcelable.Creator}
*
- * @hide
*/
- @UnsupportedAppUsage
- public static final @android.annotation.NonNull Parcelable.Creator<SignalStrength> CREATOR = new Parcelable.Creator() {
- public SignalStrength createFromParcel(Parcel in) {
- return new SignalStrength(in);
- }
+ public static final @android.annotation.NonNull Parcelable.Creator<SignalStrength> CREATOR =
+ new Parcelable.Creator<SignalStrength>() {
+ public SignalStrength createFromParcel(Parcel in) {
+ return new SignalStrength(in);
+ }
- public SignalStrength[] newArray(int size) {
- return new SignalStrength[size];
- }
+ public SignalStrength[] newArray(int size) {
+ return new SignalStrength[size];
+ }
};
/**
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 6c2dd85076fc..34966865089b 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -31,8 +31,6 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.database.CursorWindow;
import android.net.Uri;
-import android.os.Binder;
-import android.os.BaseBundle;
import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
@@ -2420,22 +2418,31 @@ public final class SmsManager {
public static final String MESSAGE_STATUS_READ = "read";
/**
- * Get carrier-dependent configuration values.
+ * Get carrier-dependent MMS configuration values.
*
* <p class="note"><strong>Note:</strong> This method is intended for internal use by carrier
- * applications or the Telephony framework and will never trigger an SMS disambiguation
- * dialog. If this method is called on a device that has multiple active subscriptions, this
- * {@link SmsManager} instance has been created with {@link #getDefault()}, and no user-defined
- * default subscription is defined, the subscription ID associated with this message will be
- * INVALID, which will result in the operation being completed on the subscription associated
- * with logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the
- * operation is performed on the correct subscription.
+ * applications or the Telephony framework and will never trigger an SMS disambiguation dialog.
+ * If this method is called on a device that has multiple active subscriptions, this {@link
+ * SmsManager} instance has been created with {@link #getDefault()}, and no user-defined default
+ * subscription is defined, the subscription ID associated with this message will be INVALID,
+ * which will result in the operation being completed on the subscription associated with
+ * logical slot 0. Use {@link #getSmsManagerForSubscriptionId(int)} to ensure the operation is
+ * performed on the correct subscription.
* </p>
*
- * @return bundle key/values pairs of configuration values
+ * @return the bundle key/values pairs that contains MMS configuration values
*/
+ @Nullable
public Bundle getCarrierConfigValues() {
- return MmsManager.getInstance().getCarrierConfigValues(getSubscriptionId());
+ try {
+ ISms iSms = getISmsService();
+ if (iSms != null) {
+ return iSms.getCarrierConfigValuesForSubscriber(getSubscriptionId());
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ return null;
}
/**
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 376a5e00ae97..d152cad966ce 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -48,7 +48,6 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.Process;
@@ -64,6 +63,7 @@ import android.util.Pair;
import com.android.internal.telephony.ISetOpportunisticDataCallback;
import com.android.internal.telephony.ISub;
import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.util.HandlerExecutor;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 85f25811b959..87bdaa9a9fe4 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -17,6 +17,8 @@
package android.telephony;
import static android.content.Context.TELECOM_SERVICE;
+import static android.provider.Telephony.Carriers.DPC_URI;
+import static android.provider.Telephony.Carriers.INVALID_APN_ID;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -44,6 +46,7 @@ import android.compat.annotation.EnabledAfter;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.NetworkStats;
import android.net.Uri;
@@ -75,6 +78,7 @@ import android.telephony.Annotation.NetworkType;
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SimActivationState;
import android.telephony.VisualVoicemailService.VisualVoicemailTask;
+import android.telephony.data.ApnSetting;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
import android.telephony.ims.ImsMmTelManager;
@@ -7573,12 +7577,12 @@ public class TelephonyManager {
/**
* Check whether DUN APN is required for tethering.
* <p>
- * Requires Permission: READ_PRIVILEGED_PHONE_STATE.
+ * Requires Permission: MODIFY_PHONE_STATE.
*
* @return {@code true} if DUN APN is required for tethering.
* @hide
*/
- @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@SystemApi
public boolean isTetheringApnRequired() {
return isTetheringApnRequired(getSubId(SubscriptionManager.getActiveDataSubscriptionId()));
@@ -10396,7 +10400,8 @@ public class TelephonyManager {
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isManualNetworkSelectionAllowed() {
try {
ITelephony telephony = getITelephony();
@@ -11671,6 +11676,88 @@ public class TelephonyManager {
}
/**
+ * Returns a list of APNs set as overrides by the device policy manager via
+ * {@link #addDevicePolicyOverrideApn}.
+ * This method must only be called from the system or phone processes.
+ *
+ * @param context Context to use.
+ * @return {@link List} of APNs that have been set as overrides.
+ * @throws {@link SecurityException} if the caller is not the system or phone process.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ // TODO: add new permission tag indicating that this is system-only.
+ public @NonNull List<ApnSetting> getDevicePolicyOverrideApns(@NonNull Context context) {
+ try (Cursor cursor = context.getContentResolver().query(DPC_URI, null, null, null, null)) {
+ if (cursor == null) {
+ return Collections.emptyList();
+ }
+ List<ApnSetting> apnList = new ArrayList<ApnSetting>();
+ cursor.moveToPosition(-1);
+ while (cursor.moveToNext()) {
+ ApnSetting apn = ApnSetting.makeApnSetting(cursor);
+ apnList.add(apn);
+ }
+ return apnList;
+ }
+ }
+
+ /**
+ * Used by the device policy manager to add a new override APN.
+ * This method must only be called from the system or phone processes.
+ *
+ * @param context Context to use.
+ * @param apnSetting The {@link ApnSetting} describing the new APN.
+ * @return An integer, corresponding to a primary key in a database, that allows the caller to
+ * modify the APN in the future via {@link #modifyDevicePolicyOverrideApn}, or
+ * {@link android.provider.Telephony.Carriers.INVALID_APN_ID} if the override operation
+ * failed.
+ * @throws {@link SecurityException} if the caller is not the system or phone process.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ // TODO: add new permission tag indicating that this is system-only.
+ public int addDevicePolicyOverrideApn(@NonNull Context context,
+ @NonNull ApnSetting apnSetting) {
+ Uri resultUri = context.getContentResolver().insert(DPC_URI, apnSetting.toContentValues());
+
+ int resultId = INVALID_APN_ID;
+ if (resultUri != null) {
+ try {
+ resultId = Integer.parseInt(resultUri.getLastPathSegment());
+ } catch (NumberFormatException e) {
+ Rlog.e(TAG, "Failed to parse inserted override APN id: "
+ + resultUri.getLastPathSegment());
+ }
+ }
+ return resultId;
+ }
+
+ /**
+ * Used by the device policy manager to modify an override APN.
+ * This method must only be called from the system or phone processes.
+ *
+ * @param context Context to use.
+ * @param apnId The integer key of the APN to modify, as returned by
+ * {@link #addDevicePolicyOverrideApn}
+ * @param apnSetting The {@link ApnSetting} describing the updated APN.
+ * @return {@code true} if successful, {@code false} otherwise.
+ * @throws {@link SecurityException} if the caller is not the system or phone process.
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ // TODO: add new permission tag indicating that this is system-only.
+ public boolean modifyDevicePolicyOverrideApn(@NonNull Context context, int apnId,
+ @NonNull ApnSetting apnSetting) {
+ return context.getContentResolver().update(
+ Uri.withAppendedPath(DPC_URI, Integer.toString(apnId)),
+ apnSetting.toContentValues(), null, null) > 0;
+ }
+
+ /**
* Return whether data is enabled for certain APN type. This will tell if framework will accept
* corresponding network requests on a subId.
*
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 034fc220cbbe..dbfb6a2a0f2e 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1056,6 +1056,11 @@ public class ApnSetting implements Parcelable {
}
/** @hide */
+ public boolean isEmergencyApn() {
+ return hasApnType(TYPE_EMERGENCY);
+ }
+
+ /** @hide */
public boolean canHandleType(@ApnType int type) {
if (!mCarrierEnabled) {
return false;
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index 4fc6a19d1f38..cfc803ca3639 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -17,7 +17,6 @@
package com.android.ims;
import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.RemoteException;
import android.telephony.Rlog;
@@ -26,6 +25,8 @@ import android.telephony.ims.ProvisioningManager;
import android.telephony.ims.aidl.IImsConfig;
import android.telephony.ims.aidl.IImsConfigCallback;
+import com.android.internal.telephony.util.HandlerExecutor;
+
import java.util.concurrent.Executor;
/**
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index 45dd5811c657..2dc59e6a7c3f 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -1,18 +1,18 @@
/*
-** Copyright 2007, 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.
-*/
+ * Copyright 2007, 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;
@@ -22,7 +22,7 @@ import android.os.Bundle;
import com.android.internal.telephony.SmsRawData;
/**
- * Interface for applications to access the ICC phone book.
+ * Service interface to handle SMS API requests
*
* See also SmsManager.java.
*/
@@ -542,6 +542,13 @@ interface ISms {
in List<PendingIntent> deliveryIntents);
/**
+ * Get carrier-dependent configuration values.
+ *
+ * @param subId the subscription Id
+ */
+ Bundle getCarrierConfigValuesForSubscriber(int subId);
+
+ /**
* Create an app-only incoming SMS request for the calling package.
*
* If an incoming text contains the token returned by this method the provided
diff --git a/telephony/java/com/android/internal/telephony/ISmsImplBase.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
index 020b92b410f1..98095bbc12ac 100644
--- a/telephony/java/com/android/internal/telephony/ISmsImplBase.java
+++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
@@ -186,6 +186,11 @@ public class ISmsImplBase extends ISms.Stub {
}
@Override
+ public Bundle getCarrierConfigValuesForSubscriber(int subId) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public String createAppSpecificSmsToken(int subId, String callingPkg, PendingIntent intent) {
throw new UnsupportedOperationException();
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 8e1a78c56e0a..48fdca7d2b8e 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -172,24 +172,6 @@ public class TelephonyIntents {
= "android.intent.action.ANY_DATA_STATE";
/**
- * Broadcast Action: An attempt to establish a data connection has failed.
- * The intent will have the following extra values:</p>
- * <dl>
- * <dt>phoneName</dt><dd>A string version of the phone name.</dd>
- * <dt>state</dt><dd>One of {@code CONNECTED}, {@code CONNECTING}, or {code DISCONNECTED}.</dd>
- * <dt>reason</dt><dd>A string indicating the reason for the failure, if available.</dd>
- * </dl>
- *
- * <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_DATA_CONNECTION_FAILED
- = "android.intent.action.DATA_CONNECTION_FAILED";
-
- /**
* Broadcast Action: The sim card state has changed.
* The intent will have the following extra values:</p>
* <dl>
diff --git a/telephony/java/com/android/internal/telephony/util/HandlerExecutor.java b/telephony/java/com/android/internal/telephony/util/HandlerExecutor.java
new file mode 100644
index 000000000000..8a2545772b5b
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/util/HandlerExecutor.java
@@ -0,0 +1,47 @@
+/*
+ * 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.os.Handler;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+/**
+ * An adapter {@link Executor} that posts all executed tasks onto the given
+ * {@link Handler}.
+ *
+ * @hide
+ */
+public class HandlerExecutor implements Executor {
+ private final Handler mHandler;
+
+ public HandlerExecutor(@NonNull Handler handler) {
+ if (handler == null) {
+ throw new NullPointerException();
+ }
+ mHandler = handler;
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ if (!mHandler.post(command)) {
+ throw new RejectedExecutionException(mHandler + " is shutting down");
+ }
+ }
+}
diff --git a/tests/TelephonyCommonTests/Android.bp b/tests/TelephonyCommonTests/Android.bp
new file mode 100644
index 000000000000..16189c8e0ac8
--- /dev/null
+++ b/tests/TelephonyCommonTests/Android.bp
@@ -0,0 +1,48 @@
+//
+// 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.
+//
+
+android_test {
+ name: "TelephonyCommonTests",
+ srcs: [
+ ":framework-telephony-common-sources",
+ "**/*.java",
+ ],
+ static_libs: [
+ "mockito-target-extended",
+ "androidx.test.rules",
+ "truth-prebuilt",
+ "platform-test-annotations",
+ "androidx.core_core",
+ "androidx.fragment_fragment",
+ "androidx.test.ext.junit"
+ ],
+
+ jni_libs: ["libdexmakerjvmtiagent"],
+
+ // We need to rename SmsApplication to the test package or else it'll get clobbered by the
+ // hidden api checker
+ jarjar_rules: "jarjar-rules.txt",
+
+ // Uncomment this and comment out the jarjar rule if you want to attach a debugger and step
+ // through the renamed classes.
+ //platform_apis: true,
+
+ libs: [
+ "android.test.runner",
+ "android.test.mock",
+ "android.test.base",
+ ],
+}
diff --git a/tests/TelephonyCommonTests/AndroidManifest.xml b/tests/TelephonyCommonTests/AndroidManifest.xml
new file mode 100644
index 000000000000..63f38c6af2cb
--- /dev/null
+++ b/tests/TelephonyCommonTests/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?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.internal.telephony.tests"
+ android:debuggable="true">
+
+ <application android:label="TelephonyCommonTests"
+ android:debuggable="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.internal.telephony.tests"
+ android:label="Telephony common tests"
+ android:debuggable="true"/>
+</manifest>
diff --git a/tests/TelephonyCommonTests/AndroidTest.xml b/tests/TelephonyCommonTests/AndroidTest.xml
new file mode 100644
index 000000000000..e9fdabcaf136
--- /dev/null
+++ b/tests/TelephonyCommonTests/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?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.
+ -->
+<configuration description="Runs Telephony Common Test Cases.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="TelephonyCommonTests.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="TelephonyCommonTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.internal.telephony.tests" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/tests/TelephonyCommonTests/jarjar-rules.txt b/tests/TelephonyCommonTests/jarjar-rules.txt
new file mode 100644
index 000000000000..fe3471973c6e
--- /dev/null
+++ b/tests/TelephonyCommonTests/jarjar-rules.txt
@@ -0,0 +1 @@
+rule com.android.internal.telephony.SmsApplication* com.android.internal.telephony.tests.SmsApplication@1
diff --git a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
new file mode 100644
index 000000000000..6d0ee1891ac9
--- /dev/null
+++ b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
@@ -0,0 +1,238 @@
+/*
+ * 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.tests;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.app.AppOpsManager;
+import android.app.role.RoleManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.UserHandle;
+import android.provider.Telephony;
+import android.telephony.TelephonyManager;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.telephony.SmsApplication;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Unit tests for the {@link SmsApplication} utility class
+ */
+@RunWith(AndroidJUnit4.class)
+public class SmsApplicationTest {
+ private static final ComponentName TEST_COMPONENT_NAME =
+ ComponentName.unflattenFromString("com.android.test/.TestSmsApp");
+ private static final String MMS_RECEIVER_NAME = "TestMmsReceiver";
+ private static final String RESPOND_VIA_SMS_NAME = "TestRespondViaSmsHandler";
+ private static final String SEND_TO_NAME = "TestSendTo";
+ private static final int SMS_APP_UID = 10001;
+
+ private static final int FAKE_PHONE_UID = 10002;
+ private static final int FAKE_MMS_UID = 10003;
+ private static final int FAKE_BT_UID = 10004;
+ private static final int FAKE_TELEPHONY_PROVIDER_UID = 10005;
+
+ private static final String[] APP_OPS_TO_CHECK = {
+ AppOpsManager.OPSTR_READ_SMS,
+ AppOpsManager.OPSTR_WRITE_SMS,
+ AppOpsManager.OPSTR_RECEIVE_SMS,
+ AppOpsManager.OPSTR_RECEIVE_WAP_PUSH,
+ AppOpsManager.OPSTR_SEND_SMS,
+ AppOpsManager.OPSTR_READ_CELL_BROADCASTS
+ };
+
+ @Mock private Context mContext;
+ @Mock private TelephonyManager mTelephonyManager;
+ @Mock private RoleManager mRoleManager;
+ @Mock private PackageManager mPackageManager;
+ @Mock private AppOpsManager mAppOpsManager;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
+ when(mContext.getSystemService(Context.ROLE_SERVICE)).thenReturn(mRoleManager);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mContext.getSystemService(RoleManager.class)).thenReturn(mRoleManager);
+ when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOpsManager);
+
+ doAnswer(invocation -> getResolveInfosForIntent(invocation.getArgument(0)))
+ .when(mPackageManager)
+ .queryBroadcastReceiversAsUser(nullable(Intent.class), anyInt(), anyInt());
+ doAnswer(invocation -> getResolveInfosForIntent(invocation.getArgument(0)))
+ .when(mPackageManager)
+ .queryIntentActivitiesAsUser(nullable(Intent.class), anyInt(), anyInt());
+ doAnswer(invocation -> getResolveInfosForIntent(invocation.getArgument(0)))
+ .when(mPackageManager)
+ .queryIntentServicesAsUser(nullable(Intent.class), anyInt(),
+ nullable(UserHandle.class));
+
+ when(mTelephonyManager.isSmsCapable()).thenReturn(true);
+ when(mRoleManager.isRoleAvailable(RoleManager.ROLE_SMS)).thenReturn(true);
+ when(mRoleManager.getDefaultSmsPackage(anyInt()))
+ .thenReturn(TEST_COMPONENT_NAME.getPackageName());
+
+ for (String opStr : APP_OPS_TO_CHECK) {
+ when(mAppOpsManager.unsafeCheckOp(
+ opStr, SMS_APP_UID, TEST_COMPONENT_NAME.getPackageName()))
+ .thenReturn(AppOpsManager.MODE_ALLOWED);
+ }
+ }
+
+ @Test
+ public void testGetDefaultSmsApplication() {
+ assertEquals(TEST_COMPONENT_NAME,
+ SmsApplication.getDefaultSmsApplicationAsUser(mContext, false, 0));
+ }
+
+ @Test
+ public void testGetDefaultSmsApplicationWithAppOpsFix() throws Exception {
+ when(mAppOpsManager.unsafeCheckOp(AppOpsManager.OPSTR_READ_SMS, SMS_APP_UID,
+ TEST_COMPONENT_NAME.getPackageName()))
+ .thenReturn(AppOpsManager.MODE_IGNORED);
+ setupPackageInfosForCoreApps();
+
+ assertEquals(TEST_COMPONENT_NAME,
+ SmsApplication.getDefaultSmsApplicationAsUser(mContext, true, 0));
+ verify(mAppOpsManager, atLeastOnce()).setUidMode(AppOpsManager.OPSTR_READ_SMS, SMS_APP_UID,
+ AppOpsManager.MODE_ALLOWED);
+ }
+
+ private void setupPackageInfosForCoreApps() throws Exception {
+ PackageInfo phonePackageInfo = new PackageInfo();
+ ApplicationInfo phoneApplicationInfo = new ApplicationInfo();
+ phoneApplicationInfo.uid = FAKE_PHONE_UID;
+ phonePackageInfo.applicationInfo = phoneApplicationInfo;
+ when(mPackageManager.getPackageInfo(eq(SmsApplication.PHONE_PACKAGE_NAME), anyInt()))
+ .thenReturn(phonePackageInfo);
+
+ PackageInfo mmsPackageInfo = new PackageInfo();
+ ApplicationInfo mmsApplicationInfo = new ApplicationInfo();
+ mmsApplicationInfo.uid = FAKE_MMS_UID;
+ mmsPackageInfo.applicationInfo = mmsApplicationInfo;
+ when(mPackageManager.getPackageInfo(eq(SmsApplication.MMS_SERVICE_PACKAGE_NAME), anyInt()))
+ .thenReturn(mmsPackageInfo);
+
+ PackageInfo bluetoothPackageInfo = new PackageInfo();
+ ApplicationInfo bluetoothApplicationInfo = new ApplicationInfo();
+ bluetoothApplicationInfo.uid = FAKE_BT_UID;
+ bluetoothPackageInfo.applicationInfo = bluetoothApplicationInfo;
+ when(mPackageManager.getPackageInfo(eq(SmsApplication.BLUETOOTH_PACKAGE_NAME), anyInt()))
+ .thenReturn(bluetoothPackageInfo);
+
+ PackageInfo telephonyProviderPackageInfo = new PackageInfo();
+ ApplicationInfo telephonyProviderApplicationInfo = new ApplicationInfo();
+ telephonyProviderApplicationInfo.uid = FAKE_TELEPHONY_PROVIDER_UID;
+ telephonyProviderPackageInfo.applicationInfo = telephonyProviderApplicationInfo;
+ when(mPackageManager.getPackageInfo(
+ eq(SmsApplication.TELEPHONY_PROVIDER_PACKAGE_NAME), anyInt()))
+ .thenReturn(telephonyProviderPackageInfo);
+ }
+
+ private List<ResolveInfo> getResolveInfosForIntent(Intent intent) {
+ switch (intent.getAction()) {
+ case Telephony.Sms.Intents.SMS_DELIVER_ACTION:
+ return Collections.singletonList(makeSmsDeliverResolveInfo());
+ case Telephony.Sms.Intents.WAP_PUSH_DELIVER_ACTION:
+ return Collections.singletonList(makeWapPushResolveInfo());
+ case TelephonyManager.ACTION_RESPOND_VIA_MESSAGE:
+ return Collections.singletonList(makeRespondViaMessageResolveInfo());
+ case Intent.ACTION_SENDTO:
+ return Collections.singletonList(makeSendToResolveInfo());
+ }
+ return Collections.emptyList();
+ }
+
+ private ApplicationInfo makeSmsApplicationInfo() {
+ ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.uid = SMS_APP_UID;
+ return applicationInfo;
+ }
+
+ private ResolveInfo makeSmsDeliverResolveInfo() {
+ ResolveInfo info = new ResolveInfo();
+ ActivityInfo activityInfo = new ActivityInfo();
+ activityInfo.applicationInfo = makeSmsApplicationInfo();
+
+ activityInfo.permission = Manifest.permission.BROADCAST_SMS;
+ activityInfo.packageName = TEST_COMPONENT_NAME.getPackageName();
+ activityInfo.name = TEST_COMPONENT_NAME.getClassName();
+
+ info.activityInfo = activityInfo;
+ return info;
+ }
+
+ private ResolveInfo makeWapPushResolveInfo() {
+ ResolveInfo info = new ResolveInfo();
+ ActivityInfo activityInfo = new ActivityInfo();
+
+ activityInfo.permission = Manifest.permission.BROADCAST_WAP_PUSH;
+ activityInfo.packageName = TEST_COMPONENT_NAME.getPackageName();
+ activityInfo.name = MMS_RECEIVER_NAME;
+
+ info.activityInfo = activityInfo;
+ return info;
+ }
+
+ private ResolveInfo makeRespondViaMessageResolveInfo() {
+ ResolveInfo info = new ResolveInfo();
+ ServiceInfo serviceInfo = new ServiceInfo();
+
+ serviceInfo.permission = Manifest.permission.SEND_RESPOND_VIA_MESSAGE;
+ serviceInfo.packageName = TEST_COMPONENT_NAME.getPackageName();
+ serviceInfo.name = RESPOND_VIA_SMS_NAME;
+
+ info.serviceInfo = serviceInfo;
+ return info;
+ }
+
+ private ResolveInfo makeSendToResolveInfo() {
+ ResolveInfo info = new ResolveInfo();
+ ActivityInfo activityInfo = new ActivityInfo();
+
+ activityInfo.packageName = TEST_COMPONENT_NAME.getPackageName();
+ activityInfo.name = SEND_TO_NAME;
+
+ info.activityInfo = activityInfo;
+ return info;
+ }
+}
diff --git a/tests/net/TEST_MAPPING b/tests/net/TEST_MAPPING
new file mode 100644
index 000000000000..a7853b68c1c1
--- /dev/null
+++ b/tests/net/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "postsubmit": [
+ {
+ "name": "FrameworksNetIntegrationTests"
+ }
+ ]
+} \ No newline at end of file
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index a7eef055a71c..a7328acb73b5 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -38,6 +38,7 @@ import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
@@ -65,6 +66,7 @@ public class LinkPropertiesTest {
private static final InetAddress GATEWAY62 = address("fe80::6:22%lo");
private static final InetAddress TESTIPV4ADDR = address("192.168.47.42");
private static final InetAddress TESTIPV6ADDR = address("fe80::7:33%43");
+ private static final Inet4Address DHCPSERVER = (Inet4Address) address("192.0.2.1");
private static final String NAME = "qmi0";
private static final String DOMAINS = "google.com";
private static final String PRIV_DNS_SERVER_NAME = "private.dns.com";
@@ -93,6 +95,7 @@ public class LinkPropertiesTest {
assertNull(lp.getHttpProxy());
assertNull(lp.getTcpBufferSizes());
assertNull(lp.getNat64Prefix());
+ assertNull(lp.getDhcpServerAddress());
assertFalse(lp.isProvisioned());
assertFalse(lp.isIpv4Provisioned());
assertFalse(lp.isIpv6Provisioned());
@@ -119,6 +122,7 @@ public class LinkPropertiesTest {
lp.setMtu(MTU);
lp.setTcpBufferSizes(TCP_BUFFER_SIZES);
lp.setNat64Prefix(new IpPrefix("2001:db8:0:64::/96"));
+ lp.setDhcpServerAddress(DHCPSERVER);
lp.setWakeOnLanSupported(true);
return lp;
}
@@ -960,11 +964,13 @@ public class LinkPropertiesTest {
source.setWakeOnLanSupported(true);
+ source.setDhcpServerAddress((Inet4Address) GATEWAY1);
+
final LinkProperties stacked = new LinkProperties();
stacked.setInterfaceName("test-stacked");
source.addStackedLink(stacked);
- assertParcelSane(source, 15 /* fieldCount */);
+ assertParcelSane(source, 16 /* fieldCount */);
}
@Test
@@ -1091,6 +1097,15 @@ public class LinkPropertiesTest {
}
@Test
+ public void testDhcpServerAddress() {
+ final LinkProperties lp = makeTestObject();
+ assertEquals(DHCPSERVER, lp.getDhcpServerAddress());
+
+ lp.clear();
+ assertNull(lp.getDhcpServerAddress());
+ }
+
+ @Test
public void testWakeOnLanSupported() {
final LinkProperties lp = makeTestObject();
assertTrue(lp.isWakeOnLanSupported());
diff --git a/tests/net/integration/Android.bp b/tests/net/integration/Android.bp
index 7d9b7b756ae3..874bd4b97df1 100644
--- a/tests/net/integration/Android.bp
+++ b/tests/net/integration/Android.bp
@@ -36,6 +36,7 @@ android_test {
"services.net",
"testables",
],
+ test_suites: ["device-tests"],
use_embedded_native_libs: true,
jni_libs: [
// For mockito extended