diff options
208 files changed, 4114 insertions, 1183 deletions
diff --git a/Android.bp b/Android.bp index 0612a5335390..27f22bde9a3a 100644 --- a/Android.bp +++ b/Android.bp @@ -613,13 +613,13 @@ filegroup { name: "framework-tethering-shared-srcs", srcs: [ "core/java/android/util/LocalLog.java", - "core/java/com/android/internal/util/BitUtils.java", "core/java/com/android/internal/util/IndentingPrintWriter.java", "core/java/com/android/internal/util/IState.java", "core/java/com/android/internal/util/MessageUtils.java", "core/java/com/android/internal/util/Preconditions.java", "core/java/com/android/internal/util/State.java", "core/java/com/android/internal/util/StateMachine.java", + "core/java/android/net/shared/Inet4AddressUtils.java", ], } diff --git a/api/current.txt b/api/current.txt index a58c4f09efeb..6dc6c7d42a98 100644 --- a/api/current.txt +++ b/api/current.txt @@ -28327,7 +28327,9 @@ package android.media.tv { method public int getVideoHeight(); method public float getVideoPixelAspectRatio(); method public int getVideoWidth(); + method public boolean isAudioDescription(); method public boolean isEncrypted(); + method public boolean isHardOfHearing(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.media.tv.TvTrackInfo> CREATOR; field public static final int TYPE_AUDIO = 0; // 0x0 @@ -28339,10 +28341,12 @@ package android.media.tv { ctor public TvTrackInfo.Builder(int, @NonNull String); method public android.media.tv.TvTrackInfo build(); method public android.media.tv.TvTrackInfo.Builder setAudioChannelCount(int); + method @NonNull public android.media.tv.TvTrackInfo.Builder setAudioDescription(boolean); method public android.media.tv.TvTrackInfo.Builder setAudioSampleRate(int); method public android.media.tv.TvTrackInfo.Builder setDescription(CharSequence); method @NonNull public android.media.tv.TvTrackInfo.Builder setEncrypted(boolean); method public android.media.tv.TvTrackInfo.Builder setExtra(android.os.Bundle); + method @NonNull public android.media.tv.TvTrackInfo.Builder setHardOfHearing(boolean); method public android.media.tv.TvTrackInfo.Builder setLanguage(String); method public android.media.tv.TvTrackInfo.Builder setVideoActiveFormatDescription(byte); method public android.media.tv.TvTrackInfo.Builder setVideoFrameRate(float); @@ -28655,6 +28659,37 @@ package android.net { field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortal> CREATOR; } + public class ConnectivityDiagnosticsManager { + method public void registerConnectivityDiagnosticsCallback(@NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback); + method public void unregisterConnectivityDiagnosticsCallback(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback); + field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1 + field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2 + } + + public abstract static class ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback { + ctor public ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback(); + method public void onConnectivityReport(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityReport); + method public void onDataStallSuspected(@NonNull android.net.ConnectivityDiagnosticsManager.DataStallReport); + method public void onNetworkConnectivityReported(@NonNull android.net.Network, boolean); + } + + public static class ConnectivityDiagnosticsManager.ConnectivityReport { + ctor public ConnectivityDiagnosticsManager.ConnectivityReport(@NonNull android.net.Network, long, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle); + field @NonNull public final android.os.PersistableBundle additionalInfo; + field @NonNull public final android.net.LinkProperties linkProperties; + field @NonNull public final android.net.Network network; + field @NonNull public final android.net.NetworkCapabilities networkCapabilities; + field public final long reportTimestamp; + } + + public static class ConnectivityDiagnosticsManager.DataStallReport { + ctor public ConnectivityDiagnosticsManager.DataStallReport(@NonNull android.net.Network, long, int, @NonNull android.os.PersistableBundle); + field public final int detectionMethod; + field @NonNull public final android.net.Network network; + field public final long reportTimestamp; + field @NonNull public final android.os.PersistableBundle stallDetails; + } + public class ConnectivityManager { method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener); method public boolean bindProcessToNetwork(@Nullable android.net.Network); @@ -35220,7 +35255,9 @@ package android.os { method public int describeContents(); method @Nullable public android.os.PersistableBundle getPersistableBundle(@Nullable String); method public void putPersistableBundle(@Nullable String, @Nullable android.os.PersistableBundle); + method @NonNull public static android.os.PersistableBundle readFromStream(@NonNull java.io.InputStream) throws java.io.IOException; method public void writeToParcel(android.os.Parcel, int); + method public void writeToStream(@NonNull java.io.OutputStream) throws java.io.IOException; field @NonNull public static final android.os.Parcelable.Creator<android.os.PersistableBundle> CREATOR; field public static final android.os.PersistableBundle EMPTY; } diff --git a/api/system-current.txt b/api/system-current.txt index 4a9154ee9875..75bdf0ce633f 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -596,6 +596,7 @@ package android.app { public class StatusBarManager { method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo(); method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean); + method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSimNetworkLock(boolean); } public static final class StatusBarManager.DisableInfo { @@ -1412,6 +1413,14 @@ package android.bluetooth { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int); } + public final class BluetoothHidHost implements android.bluetooth.BluetoothProfile { + method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice); + method public int getConnectionState(@Nullable android.bluetooth.BluetoothDevice); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@Nullable android.bluetooth.BluetoothDevice, int); + field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED"; + } + public final class BluetoothPan implements android.bluetooth.BluetoothProfile { method protected void finalize(); method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); @@ -1429,6 +1438,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"; } @@ -1544,6 +1554,7 @@ package android.content { field public static final String EUICC_CARD_SERVICE = "euicc_card"; field public static final String HDMI_CONTROL_SERVICE = "hdmi_control"; field public static final String NETD_SERVICE = "netd"; + field public static final String NETWORK_POLICY_SERVICE = "netpolicy"; field public static final String NETWORK_SCORE_SERVICE = "network_score"; field public static final String OEM_LOCK_SERVICE = "oem_lock"; field public static final String PERMISSION_SERVICE = "permission"; @@ -6111,11 +6122,13 @@ package android.os { public class UpdateEngine { ctor public UpdateEngine(); + method @NonNull public android.os.UpdateEngine.AllocateSpaceResult allocateSpace(@NonNull String, @NonNull String[]); method public void applyPayload(String, long, long, String[]); method public void applyPayload(@NonNull android.os.ParcelFileDescriptor, long, long, @NonNull String[]); method public boolean bind(android.os.UpdateEngineCallback, android.os.Handler); method public boolean bind(android.os.UpdateEngineCallback); method public void cancel(); + method public int cleanupAppliedPayload(); method public void resetStatus(); method public void resume(); method public void suspend(); @@ -6123,14 +6136,21 @@ package android.os { method public boolean verifyPayloadMetadata(String); } + public static final class UpdateEngine.AllocateSpaceResult { + method public int errorCode(); + method public long freeSpaceRequired(); + } + public static final class UpdateEngine.ErrorCodeConstants { ctor public UpdateEngine.ErrorCodeConstants(); + field public static final int DEVICE_CORRUPTED = 61; // 0x3d field public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12; // 0xc field public static final int DOWNLOAD_TRANSFER_ERROR = 9; // 0x9 field public static final int ERROR = 1; // 0x1 field public static final int FILESYSTEM_COPIER_ERROR = 4; // 0x4 field public static final int INSTALL_DEVICE_OPEN_ERROR = 7; // 0x7 field public static final int KERNEL_DEVICE_OPEN_ERROR = 8; // 0x8 + field public static final int NOT_ENOUGH_SPACE = 60; // 0x3c field public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10; // 0xa field public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6; // 0x6 field public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11; // 0xb @@ -8741,6 +8761,8 @@ package android.telephony { } public class ServiceState implements android.os.Parcelable { + method @NonNull public android.telephony.ServiceState createLocationInfoSanitizedCopy(boolean); + method public int getDataRegistrationState(); method @Nullable public android.telephony.NetworkRegistrationInfo getNetworkRegistrationInfo(int, int); method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoList(); method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForDomain(int); @@ -8893,6 +8915,8 @@ package android.telephony { public class SubscriptionManager { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean canDisablePhysicalSubscription(); + method public boolean canManageSubscription(@Nullable android.telephony.SubscriptionInfo, @Nullable String); + method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForIcc(@NonNull String); method public java.util.List<android.telephony.SubscriptionInfo> getAvailableSubscriptionInfoList(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEnabledSubscriptionId(int); method @NonNull public static android.content.res.Resources getResourcesForSubId(@NonNull android.content.Context, int); @@ -8904,6 +8928,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDefaultVoiceSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPreferredDataSubscriptionId(int, boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setSubscriptionEnabled(int, boolean); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUiccApplicationsEnabled(boolean, int); field @RequiresPermission(android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS) public static final String ACTION_SUBSCRIPTION_PLANS_CHANGED = "android.telephony.action.SUBSCRIPTION_PLANS_CHANGED"; field @NonNull public static final android.net.Uri ADVANCED_CALLING_ENABLED_CONTENT_URI; field public static final int PROFILE_CLASS_DEFAULT = -1; // 0xffffffff diff --git a/api/test-current.txt b/api/test-current.txt index 80f7e4bff61c..8de2bec0fc1c 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -352,6 +352,7 @@ package android.app { public class StatusBarManager { method @NonNull @RequiresPermission(android.Manifest.permission.STATUS_BAR) public android.app.StatusBarManager.DisableInfo getDisableInfo(); method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean); + method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSimNetworkLock(boolean); } public static final class StatusBarManager.DisableInfo { diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 28413be29a1d..dc24467406cf 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -153,6 +153,11 @@ public class StatusBarManager { */ public static final int DEFAULT_SETUP_DISABLE2_FLAGS = DISABLE2_ROTATE_SUGGESTIONS; + /** + * disable flags to be applied when the device is sim-locked. + */ + private static final int DEFAULT_SIM_LOCKED_DISABLED_FLAGS = DISABLE_EXPAND; + /** @hide */ public static final int NAVIGATION_HINT_BACK_ALT = 1 << 0; /** @hide */ @@ -385,6 +390,30 @@ public class StatusBarManager { } /** + * Enable or disable expansion of the status bar. When the device is SIM-locked, the status + * bar should not be expandable. + * + * @param disabled If {@code true}, the status bar will be set to non-expandable. If + * {@code false}, re-enables expansion of the status bar. + * @hide + */ + @SystemApi + @TestApi + @RequiresPermission(android.Manifest.permission.STATUS_BAR) + public void setDisabledForSimNetworkLock(boolean disabled) { + try { + final int userId = Binder.getCallingUserHandle().getIdentifier(); + final IStatusBarService svc = getService(); + if (svc != null) { + svc.disableForUser(disabled ? DEFAULT_SIM_LOCKED_DISABLED_FLAGS : DISABLE_NONE, + mToken, mContext.getPackageName(), userId); + } + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** * Get this app's currently requested disabled components * * @return a new DisableInfo 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 611b66bc0265..af9ece00f491 100644 --- a/core/java/android/app/timedetector/TimeDetector.java +++ b/core/java/android/app/timedetector/TimeDetector.java @@ -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/bluetooth/BluetoothHidHost.java b/core/java/android/bluetooth/BluetoothHidHost.java index 8f5cdf01f572..c1233b800a51 100644 --- a/core/java/android/bluetooth/BluetoothHidHost.java +++ b/core/java/android/bluetooth/BluetoothHidHost.java @@ -17,9 +17,12 @@ 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.SdkConstant.SdkConstantType; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.content.Context; import android.os.Binder; @@ -43,6 +46,7 @@ import java.util.List; * * @hide */ +@SystemApi public final class BluetoothHidHost implements BluetoothProfile { private static final String TAG = "BluetoothHidHost"; private static final boolean DBG = true; @@ -66,6 +70,7 @@ public final class BluetoothHidHost implements BluetoothProfile { * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to * receive. */ + @SuppressLint("ActionValue") @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED"; @@ -325,7 +330,7 @@ public final class BluetoothHidHost implements BluetoothProfile { * {@inheritDoc} */ @Override - public List<BluetoothDevice> getConnectedDevices() { + public @NonNull List<BluetoothDevice> getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); final IBluetoothHidHost service = getService(); if (service != null && isEnabled()) { @@ -342,6 +347,8 @@ public final class BluetoothHidHost implements BluetoothProfile { /** * {@inheritDoc} + * + * @hide */ @Override public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { @@ -363,7 +370,7 @@ public final class BluetoothHidHost implements BluetoothProfile { * {@inheritDoc} */ @Override - public int getConnectionState(BluetoothDevice device) { + public int getConnectionState(@Nullable BluetoothDevice device) { if (VDBG) log("getState(" + device + ")"); final IBluetoothHidHost service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { @@ -409,7 +416,7 @@ public final class BluetoothHidHost implements BluetoothProfile { */ @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) - public boolean setConnectionPolicy(BluetoothDevice device, int connectionPolicy) { + public boolean setConnectionPolicy(@Nullable BluetoothDevice device, int connectionPolicy) { if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")"); final IBluetoothHidHost service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { @@ -457,7 +464,7 @@ public final class BluetoothHidHost implements BluetoothProfile { */ @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH) - public int getConnectionPolicy(BluetoothDevice device) { + public int getConnectionPolicy(@Nullable BluetoothDevice device) { if (VDBG) log("getConnectionPolicy(" + device + ")"); final IBluetoothHidHost service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { 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/content/Context.java b/core/java/android/content/Context.java index 902c6b9dd36d..f3596411fb6b 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3918,6 +3918,7 @@ public abstract class Context { */ public static final String NETWORK_STATS_SERVICE = "netstats"; /** {@hide} */ + @SystemApi public static final String NETWORK_POLICY_SERVICE = "netpolicy"; /** {@hide} */ public static final String NETWORK_WATCHLIST_SERVICE = "network_watchlist"; diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java index cc5d3b16ff08..3e10a6c0b849 100644 --- a/core/java/android/database/AbstractCursor.java +++ b/core/java/android/database/AbstractCursor.java @@ -17,7 +17,7 @@ package android.database; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.net.Uri; import android.os.Build; diff --git a/core/java/android/database/AbstractWindowedCursor.java b/core/java/android/database/AbstractWindowedCursor.java index a988f0684fca..daf7d2b1e908 100644 --- a/core/java/android/database/AbstractWindowedCursor.java +++ b/core/java/android/database/AbstractWindowedCursor.java @@ -16,7 +16,7 @@ package android.database; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * A base class for Cursors that store their data in {@link CursorWindow}s. diff --git a/core/java/android/database/BulkCursorNative.java b/core/java/android/database/BulkCursorNative.java index 77a13cf80073..8ea450c6ca44 100644 --- a/core/java/android/database/BulkCursorNative.java +++ b/core/java/android/database/BulkCursorNative.java @@ -16,7 +16,7 @@ package android.database; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Binder; import android.os.Bundle; import android.os.IBinder; diff --git a/core/java/android/database/ContentObserver.java b/core/java/android/database/ContentObserver.java index 798b7830ac50..69ca581e1559 100644 --- a/core/java/android/database/ContentObserver.java +++ b/core/java/android/database/ContentObserver.java @@ -16,7 +16,7 @@ package android.database; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; import android.os.Handler; import android.os.UserHandle; diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java index 6873577553a7..063a2d00a306 100644 --- a/core/java/android/database/CursorWindow.java +++ b/core/java/android/database/CursorWindow.java @@ -17,7 +17,7 @@ package android.database; import android.annotation.BytesLong; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.database.sqlite.SQLiteClosable; import android.database.sqlite.SQLiteException; diff --git a/core/java/android/database/CursorWrapper.java b/core/java/android/database/CursorWrapper.java index c9cafafe4041..4496f805cc2e 100644 --- a/core/java/android/database/CursorWrapper.java +++ b/core/java/android/database/CursorWrapper.java @@ -16,7 +16,7 @@ package android.database; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.net.Uri; import android.os.Bundle; diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java index 992da312201d..4246b84dc52f 100644 --- a/core/java/android/database/DatabaseUtils.java +++ b/core/java/android/database/DatabaseUtils.java @@ -17,7 +17,7 @@ package android.database; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentValues; import android.content.Context; import android.content.OperationApplicationException; diff --git a/core/java/android/database/MatrixCursor.java b/core/java/android/database/MatrixCursor.java index b0d399c64ea9..050a49ac959e 100644 --- a/core/java/android/database/MatrixCursor.java +++ b/core/java/android/database/MatrixCursor.java @@ -16,7 +16,7 @@ package android.database; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import java.util.ArrayList; diff --git a/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java b/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java index 2af06e116da0..ba546f34c9ea 100644 --- a/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java +++ b/core/java/android/database/sqlite/DatabaseObjectNotClosedException.java @@ -16,7 +16,7 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * An exception that indicates that garbage-collector is finalizing a database object diff --git a/core/java/android/database/sqlite/SQLiteClosable.java b/core/java/android/database/sqlite/SQLiteClosable.java index d6a71da105dd..2fca729f2551 100644 --- a/core/java/android/database/sqlite/SQLiteClosable.java +++ b/core/java/android/database/sqlite/SQLiteClosable.java @@ -16,7 +16,8 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.io.Closeable; /** diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java index e3c409891c54..4559e918acc5 100644 --- a/core/java/android/database/sqlite/SQLiteCursor.java +++ b/core/java/android/database/sqlite/SQLiteCursor.java @@ -16,7 +16,7 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.database.AbstractWindowedCursor; import android.database.CursorWindow; import android.database.DatabaseUtils; diff --git a/core/java/android/database/sqlite/SQLiteCustomFunction.java b/core/java/android/database/sqlite/SQLiteCustomFunction.java index 41b78d3a7745..1ace40d7e913 100644 --- a/core/java/android/database/sqlite/SQLiteCustomFunction.java +++ b/core/java/android/database/sqlite/SQLiteCustomFunction.java @@ -16,7 +16,7 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; /** diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index caf3e9337b92..7a0e183c03fe 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -20,9 +20,9 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.ContentValues; import android.database.Cursor; diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java index fcdaf0abafcb..6a52b72a9e1c 100644 --- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java +++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java @@ -16,7 +16,7 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.util.ArrayList; import java.util.Locale; diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java index 3d0ac611b2df..165f863ccde7 100644 --- a/core/java/android/database/sqlite/SQLiteDebug.java +++ b/core/java/android/database/sqlite/SQLiteDebug.java @@ -17,14 +17,13 @@ package android.database.sqlite; import android.annotation.TestApi; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Process; import android.os.SystemProperties; import android.util.Log; import android.util.Printer; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.util.ArrayList; /** diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java index 62cec0e1aa92..943afc7e04c3 100644 --- a/core/java/android/database/sqlite/SQLiteOpenHelper.java +++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java @@ -19,7 +19,7 @@ package android.database.sqlite; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.database.DatabaseErrorHandler; import android.database.SQLException; diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java index 8304133cd41e..de1c54321985 100644 --- a/core/java/android/database/sqlite/SQLiteProgram.java +++ b/core/java/android/database/sqlite/SQLiteProgram.java @@ -16,7 +16,7 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.database.DatabaseUtils; import android.os.CancellationSignal; diff --git a/core/java/android/database/sqlite/SQLiteQueryBuilder.java b/core/java/android/database/sqlite/SQLiteQueryBuilder.java index 58901798b5f7..02c8a97a6902 100644 --- a/core/java/android/database/sqlite/SQLiteQueryBuilder.java +++ b/core/java/android/database/sqlite/SQLiteQueryBuilder.java @@ -18,7 +18,7 @@ package android.database.sqlite; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentValues; import android.database.Cursor; import android.database.DatabaseUtils; diff --git a/core/java/android/database/sqlite/SQLiteSession.java b/core/java/android/database/sqlite/SQLiteSession.java index a9ac9e7f882f..24b62b89454d 100644 --- a/core/java/android/database/sqlite/SQLiteSession.java +++ b/core/java/android/database/sqlite/SQLiteSession.java @@ -16,7 +16,7 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.database.CursorWindow; import android.database.DatabaseUtils; import android.os.CancellationSignal; diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java index 42e7ac7e8431..9fda8b011e52 100644 --- a/core/java/android/database/sqlite/SQLiteStatement.java +++ b/core/java/android/database/sqlite/SQLiteStatement.java @@ -16,7 +16,7 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.ParcelFileDescriptor; /** diff --git a/core/java/android/database/sqlite/SqliteWrapper.java b/core/java/android/database/sqlite/SqliteWrapper.java index e3171640a25c..f335fbdd89e0 100644 --- a/core/java/android/database/sqlite/SqliteWrapper.java +++ b/core/java/android/database/sqlite/SqliteWrapper.java @@ -17,12 +17,11 @@ package android.database.sqlite; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; -import android.database.sqlite.SQLiteException; import android.net.Uri; import android.util.Log; import android.widget.Toast; diff --git a/core/java/android/ddm/DdmHandleAppName.java b/core/java/android/ddm/DdmHandleAppName.java index 956078772ca8..e6fb4ec25210 100644 --- a/core/java/android/ddm/DdmHandleAppName.java +++ b/core/java/android/ddm/DdmHandleAppName.java @@ -16,11 +16,13 @@ package android.ddm; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; +import android.util.Log; + import org.apache.harmony.dalvik.ddmc.Chunk; import org.apache.harmony.dalvik.ddmc.ChunkHandler; import org.apache.harmony.dalvik.ddmc.DdmServer; -import android.util.Log; + import java.nio.ByteBuffer; diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 33e51c9fa11c..c847f86f6b62 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -16,14 +16,20 @@ package android.hardware; -import static android.system.OsConstants.*; +import static android.system.OsConstants.EACCES; +import static android.system.OsConstants.EBUSY; +import static android.system.OsConstants.EINVAL; +import static android.system.OsConstants.ENODEV; +import static android.system.OsConstants.ENOSYS; +import static android.system.OsConstants.EOPNOTSUPP; +import static android.system.OsConstants.EUSERS; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; import android.app.AppOpsManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.ImageFormat; import android.graphics.Point; diff --git a/core/java/android/hardware/HardwareBuffer.java b/core/java/android/hardware/HardwareBuffer.java index c569e05112a3..67797510870a 100644 --- a/core/java/android/hardware/HardwareBuffer.java +++ b/core/java/android/hardware/HardwareBuffer.java @@ -20,7 +20,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.LongDef; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.GraphicBuffer; import android.os.Build; import android.os.Parcel; diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java index e78fb7f00797..a71a7b63f30e 100644 --- a/core/java/android/hardware/Sensor.java +++ b/core/java/android/hardware/Sensor.java @@ -18,7 +18,7 @@ package android.hardware; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; /** diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java index 8c910b254b9c..64c45bf290ec 100644 --- a/core/java/android/hardware/SensorEvent.java +++ b/core/java/android/hardware/SensorEvent.java @@ -16,7 +16,7 @@ package android.hardware; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * This class represents a {@link android.hardware.Sensor Sensor} event and diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index 32504282d98f..6036d7938b95 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -18,7 +18,7 @@ package android.hardware; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.Handler; diff --git a/core/java/android/hardware/SerialManager.java b/core/java/android/hardware/SerialManager.java index 571c3cc0451f..b51382e01ccd 100644 --- a/core/java/android/hardware/SerialManager.java +++ b/core/java/android/hardware/SerialManager.java @@ -17,7 +17,7 @@ package android.hardware; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.ParcelFileDescriptor; import android.os.RemoteException; diff --git a/core/java/android/hardware/SerialPort.java b/core/java/android/hardware/SerialPort.java index 78ac3c007793..0fcaa4989210 100644 --- a/core/java/android/hardware/SerialPort.java +++ b/core/java/android/hardware/SerialPort.java @@ -16,12 +16,11 @@ package android.hardware; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.ParcelFileDescriptor; import java.io.FileDescriptor; import java.io.IOException; - import java.nio.ByteBuffer; /** diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java index 7abfabf4a2ac..974913b290b1 100644 --- a/core/java/android/hardware/SystemSensorManager.java +++ b/core/java/android/hardware/SystemSensorManager.java @@ -16,7 +16,7 @@ package android.hardware; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java index 27c04b407315..2333251d0802 100644 --- a/core/java/android/hardware/biometrics/BiometricConstants.java +++ b/core/java/android/hardware/biometrics/BiometricConstants.java @@ -16,8 +16,8 @@ package android.hardware.biometrics; -import android.annotation.UnsupportedAppUsage; import android.app.KeyguardManager; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java index b025508fc70e..5c74456eb60a 100644 --- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java +++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java @@ -16,8 +16,8 @@ package android.hardware.biometrics; -import android.annotation.UnsupportedAppUsage; import android.app.KeyguardManager; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.fingerprint.FingerprintManager; /** diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 48588e6d40bc..c697d4ce0c4f 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -18,7 +18,7 @@ package android.hardware.camera2; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.impl.PublicKey; import android.hardware.camera2.impl.SyntheticKey; diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 6a2fc8a2ca34..d027de88a564 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -18,7 +18,7 @@ package android.hardware.camera2; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.impl.PublicKey; import android.hardware.camera2.impl.SyntheticKey; diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index ba451e585d27..af05b2980bd9 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -18,7 +18,7 @@ package android.hardware.camera2; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.impl.CaptureResultExtras; import android.hardware.camera2.impl.PublicKey; diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index e909c0075f38..706aa4ef1979 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -16,12 +16,11 @@ package android.hardware.camera2.impl; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.ImageFormat; import android.graphics.Point; import android.graphics.Rect; import android.hardware.camera2.CameraCharacteristics; -import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.marshal.MarshalQueryable; @@ -52,7 +51,6 @@ import android.hardware.camera2.params.Face; import android.hardware.camera2.params.HighSpeedVideoConfiguration; import android.hardware.camera2.params.LensShadingMap; import android.hardware.camera2.params.MandatoryStreamCombination; -import android.hardware.camera2.params.MandatoryStreamCombination.MandatoryStreamInformation; import android.hardware.camera2.params.OisSample; import android.hardware.camera2.params.RecommendedStreamConfiguration; import android.hardware.camera2.params.RecommendedStreamConfigurationMap; diff --git a/core/java/android/hardware/camera2/utils/HashCodeHelpers.java b/core/java/android/hardware/camera2/utils/HashCodeHelpers.java index 526f086f4baa..16f3f2ab2023 100644 --- a/core/java/android/hardware/camera2/utils/HashCodeHelpers.java +++ b/core/java/android/hardware/camera2/utils/HashCodeHelpers.java @@ -16,7 +16,7 @@ package android.hardware.camera2.utils; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Provide hashing functions using the Modified Bernstein hash diff --git a/core/java/android/hardware/camera2/utils/SurfaceUtils.java b/core/java/android/hardware/camera2/utils/SurfaceUtils.java index d3c4505c37f0..abe1372ebde4 100644 --- a/core/java/android/hardware/camera2/utils/SurfaceUtils.java +++ b/core/java/android/hardware/camera2/utils/SurfaceUtils.java @@ -16,7 +16,7 @@ package android.hardware.camera2.utils; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.ImageFormat; import android.hardware.camera2.legacy.LegacyCameraDevice; import android.hardware.camera2.legacy.LegacyExceptionUtils.BufferQueueAbandonedException; diff --git a/core/java/android/hardware/camera2/utils/TypeReference.java b/core/java/android/hardware/camera2/utils/TypeReference.java index d9ba31b4c6f4..435ed153e042 100644 --- a/core/java/android/hardware/camera2/utils/TypeReference.java +++ b/core/java/android/hardware/camera2/utils/TypeReference.java @@ -16,7 +16,10 @@ package android.hardware.camera2.utils; -import android.annotation.UnsupportedAppUsage; +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.compat.annotation.UnsupportedAppUsage; + import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; @@ -24,8 +27,6 @@ import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.reflect.WildcardType; -import static com.android.internal.util.Preconditions.*; - /** * Super type token; allows capturing generic types at runtime by forcing them to be reified. * diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 0b25dbd78611..799dff9632c8 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -23,8 +23,8 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.KeyguardManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Point; import android.media.projection.MediaProjection; diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index ea63776dc5b6..2a584951887f 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -18,7 +18,7 @@ package android.hardware.display; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.ParceledListSlice; import android.content.res.Resources; diff --git a/core/java/android/hardware/display/WifiDisplay.java b/core/java/android/hardware/display/WifiDisplay.java index 55e60519707a..5bbbbf9bae77 100644 --- a/core/java/android/hardware/display/WifiDisplay.java +++ b/core/java/android/hardware/display/WifiDisplay.java @@ -16,7 +16,7 @@ package android.hardware.display; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/hardware/display/WifiDisplayStatus.java b/core/java/android/hardware/display/WifiDisplayStatus.java index 1973e51b1bba..e2a825fd990a 100644 --- a/core/java/android/hardware/display/WifiDisplayStatus.java +++ b/core/java/android/hardware/display/WifiDisplayStatus.java @@ -16,7 +16,7 @@ package android.hardware.display; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index d0622c88b4ca..315af32580aa 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -26,8 +26,8 @@ import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.biometrics.BiometricAuthenticator; diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 0c0f248e3222..8d32db013fb3 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -20,7 +20,7 @@ import android.annotation.IntDef; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.media.AudioAttributes; import android.os.Binder; diff --git a/core/java/android/hardware/location/GeofenceHardware.java b/core/java/android/hardware/location/GeofenceHardware.java index 23d8d01dbe9d..a1866af43706 100644 --- a/core/java/android/hardware/location/GeofenceHardware.java +++ b/core/java/android/hardware/location/GeofenceHardware.java @@ -16,7 +16,7 @@ package android.hardware.location; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.location.Location; import android.os.Build; import android.os.RemoteException; diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java index f96f47dfaffc..2f0265acf4bd 100644 --- a/core/java/android/hardware/soundtrigger/SoundTrigger.java +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java @@ -25,8 +25,8 @@ import static android.system.OsConstants.EPIPE; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.media.AudioFormat; import android.os.Handler; import android.os.Parcel; diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java index 911354862ff4..694d60531396 100644 --- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java +++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java @@ -16,7 +16,7 @@ package android.hardware.soundtrigger; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.Looper; import android.os.Message; diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java index 08c9eea6e012..fdb4cc079bd7 100644 --- a/core/java/android/hardware/usb/UsbDevice.java +++ b/core/java/android/hardware/usb/UsbDevice.java @@ -18,8 +18,8 @@ package android.hardware.usb; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityThread; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java index 71297c187e5c..215ac24fcb08 100644 --- a/core/java/android/hardware/usb/UsbDeviceConnection.java +++ b/core/java/android/hardware/usb/UsbDeviceConnection.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.ParcelFileDescriptor; diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java index eb148b94ac7b..73b9d1739061 100644 --- a/core/java/android/hardware/usb/UsbManager.java +++ b/core/java/android/hardware/usb/UsbManager.java @@ -26,8 +26,8 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java index 7abf3e9bcc7a..fab2c0baa10e 100644 --- a/core/java/android/hardware/usb/UsbRequest.java +++ b/core/java/android/hardware/usb/UsbRequest.java @@ -17,7 +17,7 @@ package android.hardware.usb; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.util.Log; diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java index 7d4849f7562d..9327b241c6c5 100644 --- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java @@ -16,7 +16,7 @@ package android.inputmethodservice; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.Rect; import android.os.Bundle; diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java index a47f601033cf..69b93b19fc41 100644 --- a/core/java/android/inputmethodservice/IInputMethodWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java @@ -18,7 +18,7 @@ package android.inputmethodservice; import android.annotation.BinderThread; import android.annotation.MainThread; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.os.Binder; diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 82d4d1d10d7e..44825a8f1502 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -30,9 +30,9 @@ import android.annotation.IntDef; import android.annotation.MainThread; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.Dialog; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java index 3f25113874e8..c85fcd990564 100644 --- a/core/java/android/inputmethodservice/Keyboard.java +++ b/core/java/android/inputmethodservice/Keyboard.java @@ -16,8 +16,8 @@ package android.inputmethodservice; -import android.annotation.UnsupportedAppUsage; import android.annotation.XmlRes; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java index 45f067b95298..b780b21bf3d0 100644 --- a/core/java/android/inputmethodservice/KeyboardView.java +++ b/core/java/android/inputmethodservice/KeyboardView.java @@ -16,7 +16,7 @@ package android.inputmethodservice; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java new file mode 100644 index 000000000000..6afdb5ef1b16 --- /dev/null +++ b/core/java/android/net/ConnectivityDiagnosticsManager.java @@ -0,0 +1,242 @@ +/* + * 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; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.PersistableBundle; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.concurrent.Executor; + +/** + * Class that provides utilities for collecting network connectivity diagnostics information. + * Connectivity information is made available through triggerable diagnostics tools and by listening + * to System validations. Some diagnostics information may be permissions-restricted. + * + * <p>ConnectivityDiagnosticsManager is intended for use by applications offering network + * connectivity on a user device. These tools will provide several mechanisms for these applications + * to be alerted to network conditions as well as diagnose potential network issues themselves. + * + * <p>The primary responsibilities of this class are to: + * + * <ul> + * <li>Allow permissioned applications to register and unregister callbacks for network event + * notifications + * <li>Invoke callbacks for network event notifications, including: + * <ul> + * <li>Network validations + * <li>Data stalls + * <li>Connectivity reports from applications + * </ul> + * </ul> + */ +public class ConnectivityDiagnosticsManager { + public static final int DETECTION_METHOD_DNS_EVENTS = 1; + public static final int DETECTION_METHOD_TCP_METRICS = 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = {"DETECTION_METHOD_"}, + value = {DETECTION_METHOD_DNS_EVENTS, DETECTION_METHOD_TCP_METRICS}) + public @interface DetectionMethod {} + + /** @hide */ + public ConnectivityDiagnosticsManager() {} + + /** Class that includes connectivity information for a specific Network at a specific time. */ + public static class ConnectivityReport { + /** The Network for which this ConnectivityReport applied */ + @NonNull public final Network network; + + /** + * The timestamp for the report. The timestamp is taken from {@link + * System#currentTimeMillis}. + */ + public final long reportTimestamp; + + /** LinkProperties available on the Network at the reported timestamp */ + @NonNull public final LinkProperties linkProperties; + + /** NetworkCapabilities available on the Network at the reported timestamp */ + @NonNull public final NetworkCapabilities networkCapabilities; + + /** PersistableBundle that may contain additional info about the report */ + @NonNull public final PersistableBundle additionalInfo; + + /** + * Constructor for ConnectivityReport. + * + * <p>Apps should obtain instances through {@link + * ConnectivityDiagnosticsCallback#onConnectivityReport} instead of instantiating their own + * instances (unless for testing purposes). + * + * @param network The Network for which this ConnectivityReport applies + * @param reportTimestamp The timestamp for the report + * @param linkProperties The LinkProperties available on network at reportTimestamp + * @param networkCapabilities The NetworkCapabilities available on network at + * reportTimestamp + * @param additionalInfo A PersistableBundle that may contain additional info about the + * report + */ + public ConnectivityReport( + @NonNull Network network, + long reportTimestamp, + @NonNull LinkProperties linkProperties, + @NonNull NetworkCapabilities networkCapabilities, + @NonNull PersistableBundle additionalInfo) { + this.network = network; + this.reportTimestamp = reportTimestamp; + this.linkProperties = linkProperties; + this.networkCapabilities = networkCapabilities; + this.additionalInfo = additionalInfo; + } + } + + /** Class that includes information for a suspected data stall on a specific Network */ + public static class DataStallReport { + /** The Network for which this DataStallReport applied */ + @NonNull public final Network network; + + /** + * The timestamp for the report. The timestamp is taken from {@link + * System#currentTimeMillis}. + */ + public final long reportTimestamp; + + /** The detection method used to identify the suspected data stall */ + @DetectionMethod public final int detectionMethod; + + /** PersistableBundle that may contain additional information on the suspected data stall */ + @NonNull public final PersistableBundle stallDetails; + + /** + * Constructor for DataStallReport. + * + * <p>Apps should obtain instances through {@link + * ConnectivityDiagnosticsCallback#onDataStallSuspected} instead of instantiating their own + * instances (unless for testing purposes). + * + * @param network The Network for which this DataStallReport applies + * @param reportTimestamp The timestamp for the report + * @param detectionMethod The detection method used to identify this data stall + * @param stallDetails A PersistableBundle that may contain additional info about the report + */ + public DataStallReport( + @NonNull Network network, + long reportTimestamp, + @DetectionMethod int detectionMethod, + @NonNull PersistableBundle stallDetails) { + this.network = network; + this.reportTimestamp = reportTimestamp; + this.detectionMethod = detectionMethod; + this.stallDetails = stallDetails; + } + } + + /** + * Abstract base class for Connectivity Diagnostics callbacks. Used for notifications about + * network connectivity events. Must be extended by applications wanting notifications. + */ + public abstract static class ConnectivityDiagnosticsCallback { + /** + * Called when the platform completes a data connectivity check. This will also be invoked + * upon registration with the latest report. + * + * <p>The Network specified in the ConnectivityReport may not be active any more when this + * method is invoked. + * + * @param report The ConnectivityReport containing information about a connectivity check + */ + public void onConnectivityReport(@NonNull ConnectivityReport report) {} + + /** + * Called when the platform suspects a data stall on some Network. + * + * <p>The Network specified in the DataStallReport may not be active any more when this + * method is invoked. + * + * @param report The DataStallReport containing information about the suspected data stall + */ + public void onDataStallSuspected(@NonNull DataStallReport report) {} + + /** + * Called when any app reports connectivity to the System. + * + * @param network The Network for which connectivity has been reported + * @param hasConnectivity The connectivity reported to the System + */ + public void onNetworkConnectivityReported( + @NonNull Network network, boolean hasConnectivity) {} + } + + /** + * Registers a ConnectivityDiagnosticsCallback with the System. + * + * <p>Only apps that offer network connectivity to the user are allowed to register callbacks. + * This includes: + * + * <ul> + * <li>Carrier apps with active subscriptions + * <li>Active VPNs + * <li>WiFi Suggesters + * </ul> + * + * <p>Callbacks will be limited to receiving notifications for networks over which apps provide + * connectivity. + * + * <p>If a registering app loses its relevant permissions, any callbacks it registered will + * silently stop receiving callbacks. + * + * <p>Each register() call <b>MUST</b> use a unique ConnectivityDiagnosticsCallback instance. If + * a single instance is registered with multiple NetworkRequests, an IllegalArgumentException + * will be thrown. + * + * @param request The NetworkRequest that will be used to match with Networks for which + * callbacks will be fired + * @param e The Executor to be used for running the callback method invocations + * @param callback The ConnectivityDiagnosticsCallback that the caller wants registered with the + * System + * @throws IllegalArgumentException if the same callback instance is registered with multiple + * NetworkRequests + * @throws SecurityException if the caller does not have appropriate permissions to register a + * callback + */ + public void registerConnectivityDiagnosticsCallback( + @NonNull NetworkRequest request, + @NonNull Executor e, + @NonNull ConnectivityDiagnosticsCallback callback) { + // TODO(b/143187964): implement ConnectivityDiagnostics functionality + throw new UnsupportedOperationException("registerCallback() not supported yet"); + } + + /** + * Unregisters a ConnectivityDiagnosticsCallback with the System. + * + * <p>If the given callback is not currently registered with the System, this operation will be + * a no-op. + * + * @param callback The ConnectivityDiagnosticsCallback to be unregistered from the System. + */ + public void unregisterConnectivityDiagnosticsCallback( + @NonNull ConnectivityDiagnosticsCallback callback) { + // TODO(b/143187964): implement ConnectivityDiagnostics functionality + throw new UnsupportedOperationException("registerCallback() not supported yet"); + } +} diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 82cecb6f20ad..6806d780c506 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -27,8 +27,8 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.PendingIntent; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.net.IpSecManager.UdpEncapsulationSocket; diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java index 97be51a30641..059cd94accfe 100644 --- a/core/java/android/net/DhcpResults.java +++ b/core/java/android/net/DhcpResults.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.shared.InetAddressUtils; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 72565024d3a5..fd015b4fe52c 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -17,7 +17,7 @@ package android.net; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Handler; import android.os.Message; diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java index 1ae44e169851..37425ffc18aa 100644 --- a/core/java/android/net/InterfaceConfiguration.java +++ b/core/java/android/net/InterfaceConfiguration.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java index dddb64d8cece..23d5ff7f3afe 100644 --- a/core/java/android/net/IpConfiguration.java +++ b/core/java/android/net/IpConfiguration.java @@ -20,8 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; -import android.net.StaticIpConfiguration; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index 93dd2e4d7717..bf8b38fc7f84 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -30,7 +30,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 89ec3e776d41..2792c564988a 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/LinkQualityInfo.java b/core/java/android/net/LinkQualityInfo.java index 2e6915ff4aa5..aa56cff50f63 100644 --- a/core/java/android/net/LinkQualityInfo.java +++ b/core/java/android/net/LinkQualityInfo.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/LocalSocket.java b/core/java/android/net/LocalSocket.java index 6a2031b4131d..5b38f78782a8 100644 --- a/core/java/android/net/LocalSocket.java +++ b/core/java/android/net/LocalSocket.java @@ -16,7 +16,8 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.io.Closeable; import java.io.FileDescriptor; import java.io.IOException; diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java index b066a15106af..e80e3a6f93ec 100644 --- a/core/java/android/net/LocalSocketImpl.java +++ b/core/java/android/net/LocalSocketImpl.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.system.ErrnoException; import android.system.Int32Ref; import android.system.Os; diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java index 87295142bec4..74c9aac05b41 100644 --- a/core/java/android/net/MacAddress.java +++ b/core/java/android/net/MacAddress.java @@ -19,7 +19,7 @@ package android.net; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.wifi.WifiInfo; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/MobileLinkQualityInfo.java b/core/java/android/net/MobileLinkQualityInfo.java index a10a14d750d8..a65de6bb2908 100644 --- a/core/java/android/net/MobileLinkQualityInfo.java +++ b/core/java/android/net/MobileLinkQualityInfo.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; /** diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index f12ba1367d98..8d1ab332ce12 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -19,7 +19,7 @@ package android.net; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.system.ErrnoException; diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index ff4bf2d3474c..60bd5730f8cf 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -17,7 +17,7 @@ package android.net; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.Bundle; diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 421e61b76fab..a5e567d274c1 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -21,7 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.ConnectivityManager.NetworkCallback; import android.os.Build; import android.os.Parcel; diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java index 5b1d12c603b4..42ab9256a6ab 100644 --- a/core/java/android/net/NetworkFactory.java +++ b/core/java/android/net/NetworkFactory.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; import android.os.Handler; diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index 92f105f77172..d0c536316527 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -17,7 +17,7 @@ package android.net; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java index 33baebbbe857..4f05c9bbb2e3 100644 --- a/core/java/android/net/NetworkPolicy.java +++ b/core/java/android/net/NetworkPolicy.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.BackupUtils; diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index bf272625e713..ca4caf63f23c 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -19,8 +19,8 @@ package android.net; import static android.content.pm.PackageManager.GET_SIGNATURES; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; diff --git a/core/java/android/net/NetworkQuotaInfo.java b/core/java/android/net/NetworkQuotaInfo.java index a46cddeda2dd..2e52d9cd19ab 100644 --- a/core/java/android/net/NetworkQuotaInfo.java +++ b/core/java/android/net/NetworkQuotaInfo.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 471b23e04775..0c83368a2970 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.NetworkCapabilities.NetCapability; import android.net.NetworkCapabilities.Transport; import android.os.Build; diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java index 292cf50ac4ae..e44961528708 100644 --- a/core/java/android/net/NetworkState.java +++ b/core/java/android/net/NetworkState.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 6c7aa1379fb1..45bf4d2e1358 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -19,7 +19,7 @@ package android.net; import static android.os.Process.CLAT_UID; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index f61260ee3ed0..7b799e262419 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -30,7 +30,7 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.internal.util.ArrayUtils.total; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.service.NetworkStatsHistoryBucketProto; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 87c7118c0ed8..5e6c47a47a8e 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -34,7 +34,7 @@ import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.removeDoubleQuotes; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.BackupUtils; diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index d0f54b4c7f2d..08cc4e24b245 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -20,7 +20,7 @@ import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.shared.Inet4AddressUtils; import android.os.Build; import android.system.ErrnoException; @@ -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/Proxy.java b/core/java/android/net/Proxy.java index 4600942806a8..4ba7394a4bb2 100644 --- a/core/java/android/net/Proxy.java +++ b/core/java/android/net/Proxy.java @@ -18,7 +18,7 @@ package android.net; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.text.TextUtils; import android.util.Log; diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java index 9d92db448668..ffe9ae9521a8 100644 --- a/core/java/android/net/ProxyInfo.java +++ b/core/java/android/net/ProxyInfo.java @@ -18,7 +18,7 @@ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 52d3fc48a3a5..ea6002ca29e6 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -21,7 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index 39cb323d0662..8b6ac4271c30 100644 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ b/core/java/android/net/SSLCertificateSocketFactory.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.SystemProperties; import android.util.Log; diff --git a/core/java/android/net/SSLSessionCache.java b/core/java/android/net/SSLSessionCache.java index 9667e82c988c..944bc549acca 100644 --- a/core/java/android/net/SSLSessionCache.java +++ b/core/java/android/net/SSLSessionCache.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.util.Log; diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java index f9c2defc0377..8c6faf6d9970 100644 --- a/core/java/android/net/SntpClient.java +++ b/core/java/android/net/SntpClient.java @@ -16,7 +16,7 @@ package android.net; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.SystemClock; import android.util.Log; diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java index 990c1142284c..f24a9bd53039 100644 --- a/core/java/android/net/StaticIpConfiguration.java +++ b/core/java/android/net/StaticIpConfiguration.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.shared.InetAddressUtils; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index bf4884aa96a7..162d6e27bd42 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -20,10 +20,10 @@ import android.annotation.NonNull; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.DownloadManager; import android.app.backup.BackupManager; import android.app.usage.NetworkStatsManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.media.MediaPlayer; import android.os.Build; diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java index c3166e91fac7..ddca4b464123 100644 --- a/core/java/android/net/Uri.java +++ b/core/java/android/net/Uri.java @@ -19,7 +19,7 @@ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.os.Environment; import android.os.Parcel; diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java index ed7cddcc6036..4b804b097d59 100644 --- a/core/java/android/net/VpnService.java +++ b/core/java/android/net/VpnService.java @@ -23,11 +23,11 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.PendingIntent; import android.app.Service; import android.app.admin.DevicePolicyManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/core/java/android/net/WebAddress.java b/core/java/android/net/WebAddress.java index 994c794e6997..aa3777d55342 100644 --- a/core/java/android/net/WebAddress.java +++ b/core/java/android/net/WebAddress.java @@ -20,7 +20,7 @@ import static android.util.Patterns.GOOD_IRI_CHAR; import android.annotation.NonNull; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import java.util.Locale; 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/net/http/SslCertificate.java b/core/java/android/net/http/SslCertificate.java index 01dd08f4ad9c..250cff29944a 100644 --- a/core/java/android/net/http/SslCertificate.java +++ b/core/java/android/net/http/SslCertificate.java @@ -17,7 +17,7 @@ package android.net.http; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Bundle; import android.text.format.DateFormat; diff --git a/core/java/android/net/http/SslError.java b/core/java/android/net/http/SslError.java index b3f2fb79b5c3..d43c616a4f13 100644 --- a/core/java/android/net/http/SslError.java +++ b/core/java/android/net/http/SslError.java @@ -16,8 +16,9 @@ package android.net.http; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; + import java.security.cert.X509Certificate; /** diff --git a/core/java/android/net/metrics/ApfProgramEvent.java b/core/java/android/net/metrics/ApfProgramEvent.java index 8243be9c1355..f93907a37f3f 100644 --- a/core/java/android/net/metrics/ApfProgramEvent.java +++ b/core/java/android/net/metrics/ApfProgramEvent.java @@ -21,7 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; diff --git a/core/java/android/net/metrics/ApfStats.java b/core/java/android/net/metrics/ApfStats.java index eac5579f9eaa..b221cb97b28f 100644 --- a/core/java/android/net/metrics/ApfStats.java +++ b/core/java/android/net/metrics/ApfStats.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/core/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java index 5f9f50708a49..8fc1ef80bba9 100644 --- a/core/java/android/net/metrics/DhcpClientEvent.java +++ b/core/java/android/net/metrics/DhcpClientEvent.java @@ -20,7 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java index 6f1bf71f187b..29aaf534eda1 100644 --- a/core/java/android/os/PersistableBundle.java +++ b/core/java/android/os/PersistableBundle.java @@ -16,17 +16,24 @@ package android.os; +import static java.nio.charset.StandardCharsets.UTF_8; + +import android.annotation.NonNull; import android.annotation.Nullable; import android.util.ArrayMap; import android.util.proto.ProtoOutputStream; +import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlPullParserFactory; import org.xmlpull.v1.XmlSerializer; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.ArrayList; /** @@ -339,4 +346,44 @@ public final class PersistableBundle extends BaseBundle implements Cloneable, Pa proto.end(token); } + + /** + * Writes the content of the {@link PersistableBundle} to a {@link OutputStream}. + * + * <p>The content can be read by a {@link #readFromStream}. + * + * @see #readFromStream + */ + public void writeToStream(@NonNull OutputStream outputStream) throws IOException { + FastXmlSerializer serializer = new FastXmlSerializer(); + serializer.setOutput(outputStream, UTF_8.name()); + serializer.startTag(null, "bundle"); + try { + saveToXml(serializer); + } catch (XmlPullParserException e) { + throw new IOException(e); + } + serializer.endTag(null, "bundle"); + serializer.flush(); + } + + /** + * Reads a {@link PersistableBundle} from an {@link InputStream}. + * + * <p>The stream must be generated by {@link #writeToStream}. + * + * @see #writeToStream + */ + @NonNull + public static PersistableBundle readFromStream(@NonNull InputStream inputStream) + throws IOException { + try { + XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); + parser.setInput(inputStream, UTF_8.name()); + parser.next(); + return PersistableBundle.restoreFromXml(parser); + } catch (XmlPullParserException e) { + throw new IOException(e); + } + } } diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java index a9ddffe7d55c..16f7b398731c 100644 --- a/core/java/android/os/UpdateEngine.java +++ b/core/java/android/os/UpdateEngine.java @@ -16,6 +16,7 @@ package android.os; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.IUpdateEngine; @@ -140,8 +141,43 @@ public class UpdateEngine { * {@code SWITCH_SLOT_ON_REBOOT=0}. See {@link #applyPayload}. */ public static final int UPDATED_BUT_NOT_ACTIVE = 52; + + /** + * Error code: there is not enough space on the device to apply the update. User should + * be prompted to free up space and re-try the update. + * + * <p>See {@link UpdateEngine#allocateSpace}. + */ + public static final int NOT_ENOUGH_SPACE = 60; + + /** + * Error code: the device is corrupted and no further updates may be applied. + * + * <p>See {@link UpdateEngine#cleanupAppliedPayload}. + */ + public static final int DEVICE_CORRUPTED = 61; } + /** @hide */ + @IntDef(value = { + ErrorCodeConstants.SUCCESS, + ErrorCodeConstants.ERROR, + ErrorCodeConstants.FILESYSTEM_COPIER_ERROR, + ErrorCodeConstants.POST_INSTALL_RUNNER_ERROR, + ErrorCodeConstants.PAYLOAD_MISMATCHED_TYPE_ERROR, + ErrorCodeConstants.INSTALL_DEVICE_OPEN_ERROR, + ErrorCodeConstants.KERNEL_DEVICE_OPEN_ERROR, + ErrorCodeConstants.DOWNLOAD_TRANSFER_ERROR, + ErrorCodeConstants.PAYLOAD_HASH_MISMATCH_ERROR, + ErrorCodeConstants.PAYLOAD_SIZE_MISMATCH_ERROR, + ErrorCodeConstants.DOWNLOAD_PAYLOAD_VERIFICATION_ERROR, + ErrorCodeConstants.PAYLOAD_TIMESTAMP_ERROR, + ErrorCodeConstants.UPDATED_BUT_NOT_ACTIVE, + ErrorCodeConstants.NOT_ENOUGH_SPACE, + ErrorCodeConstants.DEVICE_CORRUPTED, + }) + public @interface ErrorCode {} + /** * Status codes for update engine. Values must agree with the ones in * {@code system/update_engine/client_library/include/update_engine/update_status.h}. @@ -419,4 +455,138 @@ public class UpdateEngine { throw e.rethrowFromSystemServer(); } } + + /** + * Return value of {@link #allocateSpace.} + */ + public static final class AllocateSpaceResult { + private @ErrorCode int mErrorCode = ErrorCodeConstants.SUCCESS; + private long mFreeSpaceRequired = 0; + private AllocateSpaceResult() {} + /** + * Error code. + * + * @return The following error codes: + * <ul> + * <li>{@link ErrorCodeConstants#SUCCESS} if space has been allocated + * successfully.</li> + * <li>{@link ErrorCodeConstants#NOT_ENOUGH_SPACE} if insufficient + * space.</li> + * <li>Other {@link ErrorCodeConstants} for other errors.</li> + * </ul> + */ + @ErrorCode + public int errorCode() { + return mErrorCode; + } + + /** + * Estimated total space that needs to be available on the userdata partition to apply the + * payload (in bytes). + * + * <p> + * Note that in practice, more space needs to be made available before applying the payload + * to keep the device working. + * + * @return The following values: + * <ul> + * <li>zero if {@link #errorCode} returns {@link ErrorCodeConstants#SUCCESS}</li> + * <li>non-zero if {@link #errorCode} returns {@link ErrorCodeConstants#NOT_ENOUGH_SPACE}. + * Value is the estimated total space required on userdata partition.</li> + * </ul> + * @throws IllegalStateException if {@link #errorCode} is not one of the above. + * + */ + public long freeSpaceRequired() { + if (mErrorCode == ErrorCodeConstants.SUCCESS) { + return 0; + } + if (mErrorCode == ErrorCodeConstants.NOT_ENOUGH_SPACE) { + return mFreeSpaceRequired; + } + throw new IllegalStateException(String.format( + "freeSpaceRequired() is not available when error code is %d", mErrorCode)); + } + } + + /** + * Initialize partitions for a payload associated with the given payload + * metadata {@code payloadMetadataFilename} by preallocating required space. + * + * <p>This function should be called after payload has been verified after + * {@link #verifyPayloadMetadata}. This function does not verify whether + * the given payload is applicable or not. + * + * <p>Implementation of {@code allocateSpace} uses + * {@code headerKeyValuePairs} to determine whether space has been allocated + * for a different or same payload previously. If space has been allocated + * for a different payload before, space will be reallocated for the given + * payload. If space has been allocated for the same payload, no actions to + * storage devices are taken. + * + * <p>This function is synchronous and may take a non-trivial amount of + * time. Callers should call this function in a background thread. + * + * @param payloadMetadataFilename See {@link #verifyPayloadMetadata}. + * @param headerKeyValuePairs See {@link #applyPayload}. + * @return See {@link AllocateSpaceResult}. + */ + @NonNull + public AllocateSpaceResult allocateSpace( + @NonNull String payloadMetadataFilename, + @NonNull String[] headerKeyValuePairs) { + AllocateSpaceResult result = new AllocateSpaceResult(); + try { + result.mFreeSpaceRequired = mUpdateEngine.allocateSpaceForPayload( + payloadMetadataFilename, + headerKeyValuePairs); + result.mErrorCode = result.mFreeSpaceRequired == 0 + ? ErrorCodeConstants.SUCCESS + : ErrorCodeConstants.NOT_ENOUGH_SPACE; + return result; + } catch (ServiceSpecificException e) { + result.mErrorCode = e.errorCode; + result.mFreeSpaceRequired = 0; + return result; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Cleanup files used by the previous update and free up space after the + * device has been booted successfully into the new build. + * + * <p>In particular, this function waits until delta files for snapshots for + * Virtual A/B update are merged to OS partitions, then delete these delta + * files. + * + * <p>This function is synchronous and may take a non-trivial amount of + * time. Callers should call this function in a background thread. + * + * <p>This function does not delete payload binaries downloaded for a + * non-streaming OTA update. + * + * @return One of the following: + * <ul> + * <li>{@link ErrorCodeConstants#SUCCESS} if execution is successful.</li> + * <li>{@link ErrorCodeConstants#ERROR} if a transient error has occurred. + * The device should be able to recover after a reboot. The function should + * be retried after the reboot.</li> + * <li>{@link ErrorCodeConstants#DEVICE_CORRUPTED} if a permanent error is + * encountered. Device is corrupted, and future updates must not be applied. + * The device cannot recover without flashing and factory resets. + * </ul> + * + * @throws ServiceSpecificException if other transient errors has occurred. + * A reboot may or may not help resolving the issue. + */ + @ErrorCode + public int cleanupAppliedPayload() { + try { + return mUpdateEngine.cleanupSuccessfulUpdate(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/os/UpdateEngineCallback.java b/core/java/android/os/UpdateEngineCallback.java index f07294e222e2..7fe7024f25b3 100644 --- a/core/java/android/os/UpdateEngineCallback.java +++ b/core/java/android/os/UpdateEngineCallback.java @@ -44,5 +44,6 @@ public abstract class UpdateEngineCallback { * unsuccessfully. The value of {@code errorCode} will be one of the * values from {@link UpdateEngine.ErrorCodeConstants}. */ - public abstract void onPayloadApplicationComplete(int errorCode); + public abstract void onPayloadApplicationComplete( + @UpdateEngine.ErrorCode int errorCode); } diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index c11a99d231d5..fc2dfb833a8f 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -23,6 +23,8 @@ import android.annotation.TestApi; import android.content.Context; import android.os.Binder; import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerExecutor; import android.os.RemoteException; import android.os.ServiceManager; import android.telephony.Annotation.CallState; 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/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index 8a1fd62c0201..c67fca59fe97 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -870,6 +870,94 @@ public class ViewDebug { return null; } + private static class StreamingPictureCallbackHandler implements AutoCloseable, + HardwareRenderer.PictureCapturedCallback, Runnable { + private final HardwareRenderer mRenderer; + private final Callable<OutputStream> mCallback; + private final Executor mExecutor; + private final ReentrantLock mLock = new ReentrantLock(false); + private final ArrayDeque<byte[]> mQueue = new ArrayDeque<>(3); + private final ByteArrayOutputStream mByteStream = new ByteArrayOutputStream(); + private boolean mStopListening; + private Thread mRenderThread; + + private StreamingPictureCallbackHandler(HardwareRenderer renderer, + Callable<OutputStream> callback, Executor executor) { + mRenderer = renderer; + mCallback = callback; + mExecutor = executor; + mRenderer.setPictureCaptureCallback(this); + } + + @Override + public void close() { + mLock.lock(); + mStopListening = true; + mLock.unlock(); + mRenderer.setPictureCaptureCallback(null); + } + + @Override + public void onPictureCaptured(Picture picture) { + mLock.lock(); + if (mStopListening) { + mLock.unlock(); + mRenderer.setPictureCaptureCallback(null); + return; + } + if (mRenderThread == null) { + mRenderThread = Thread.currentThread(); + } + boolean needsInvoke = true; + if (mQueue.size() == 3) { + mQueue.removeLast(); + needsInvoke = false; + } + picture.writeToStream(mByteStream); + mQueue.add(mByteStream.toByteArray()); + mByteStream.reset(); + mLock.unlock(); + + if (needsInvoke) { + mExecutor.execute(this); + } + } + + @Override + public void run() { + mLock.lock(); + final byte[] picture = mQueue.poll(); + final boolean isStopped = mStopListening; + mLock.unlock(); + if (Thread.currentThread() == mRenderThread) { + close(); + throw new IllegalStateException( + "ViewDebug#startRenderingCommandsCapture must be given an executor that " + + "invokes asynchronously"); + } + if (isStopped) { + return; + } + OutputStream stream = null; + try { + stream = mCallback.call(); + } catch (Exception ex) { + Log.w("ViewDebug", "Aborting rendering commands capture " + + "because callback threw exception", ex); + } + if (stream != null) { + try { + stream.write(picture); + } catch (IOException ex) { + Log.w("ViewDebug", "Aborting rendering commands capture " + + "due to IOException writing to output stream", ex); + } + } else { + close(); + } + } + } + /** * Begins capturing the entire rendering commands for the view tree referenced by the given * view. The view passed may be any View in the tree as long as it is attached. That is, @@ -915,18 +1003,7 @@ public class ViewDebug { } final HardwareRenderer renderer = attachInfo.mThreadedRenderer; if (renderer != null) { - return new PictureCallbackHandler(renderer, (picture -> { - try { - OutputStream stream = callback.call(); - if (stream != null) { - picture.writeToStream(stream); - return true; - } - } catch (Exception ex) { - // fall through - } - return false; - }), executor); + return new StreamingPictureCallbackHandler(renderer, callback, executor); } return null; } diff --git a/core/java/com/android/internal/compat/AndroidBuildClassifier.java b/core/java/com/android/internal/compat/AndroidBuildClassifier.java new file mode 100644 index 000000000000..0b937fad7df1 --- /dev/null +++ b/core/java/com/android/internal/compat/AndroidBuildClassifier.java @@ -0,0 +1,34 @@ +/* + * 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.compat; + +import android.os.Build; + +/** + * Platform private class for determining the type of Android build installed. + * + */ +public class AndroidBuildClassifier { + + public boolean isDebuggableBuild() { + return Build.IS_DEBUGGABLE; + } + + public boolean isFinalBuild() { + return "REL".equals(Build.VERSION.CODENAME); + } +} diff --git a/core/java/com/android/internal/compat/IOverrideValidator.aidl b/core/java/com/android/internal/compat/IOverrideValidator.aidl new file mode 100644 index 000000000000..add4708863aa --- /dev/null +++ b/core/java/com/android/internal/compat/IOverrideValidator.aidl @@ -0,0 +1,38 @@ +/* + * 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.compat; + +import android.content.pm.ApplicationInfo; + +import com.android.internal.compat.OverrideAllowedState; + +/** + * Platform private API for determining whether a changeId can be overridden. + * + * {@hide} + */ +interface IOverrideValidator +{ + /** + * Validation function. + * @param changeId id of the change to be toggled on or off. + * @param packageName package of the app for which the change should be overridden. + * @return {@link OverrideAllowedState} specifying whether the change can be overridden for + * the given package or a reason why not. + */ + OverrideAllowedState getOverrideAllowedState(long changeId, String packageName); +} diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl index 7dcb12c9e72b..4c203d394759 100644 --- a/core/java/com/android/internal/compat/IPlatformCompat.aidl +++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl @@ -17,6 +17,7 @@ package com.android.internal.compat; import android.content.pm.ApplicationInfo; +import com.android.internal.compat.IOverrideValidator; import java.util.Map; parcelable CompatibilityChangeConfig; @@ -195,4 +196,9 @@ interface IPlatformCompat * @return An array of {@link CompatChangeInfo} known to the service. */ CompatibilityChangeInfo[] listAllChanges(); + + /** + * Get an instance that can determine whether a changeid can be overridden for a package name. + */ + IOverrideValidator getOverrideValidator(); } diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.aidl b/core/java/com/android/internal/compat/OverrideAllowedState.aidl new file mode 100644 index 000000000000..10ceac786841 --- /dev/null +++ b/core/java/com/android/internal/compat/OverrideAllowedState.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 com.android.internal.compat; + +parcelable OverrideAllowedState;
\ No newline at end of file diff --git a/core/java/com/android/internal/compat/OverrideAllowedState.java b/core/java/com/android/internal/compat/OverrideAllowedState.java new file mode 100644 index 000000000000..56216c251070 --- /dev/null +++ b/core/java/com/android/internal/compat/OverrideAllowedState.java @@ -0,0 +1,153 @@ +/* + * 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.compat; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * This class contains all the possible override allowed states. + */ +public final class OverrideAllowedState implements Parcelable { + @IntDef({ + ALLOWED, + DISABLED_NOT_DEBUGGABLE, + DISABLED_NON_TARGET_SDK, + DISABLED_TARGET_SDK_TOO_HIGH, + PACKAGE_DOES_NOT_EXIST + }) + @Retention(RetentionPolicy.SOURCE) + public @interface State { + } + + /** + * Change can be overridden. + */ + public static final int ALLOWED = 0; + /** + * Change cannot be overridden, due to the app not being debuggable. + */ + public static final int DISABLED_NOT_DEBUGGABLE = 1; + /** + * Change cannot be overridden, due to the build being non-debuggable and the change being + * non-targetSdk. + */ + public static final int DISABLED_NON_TARGET_SDK = 2; + /** + * Change cannot be overridden, due to the app's targetSdk being above the change's targetSdk. + */ + public static final int DISABLED_TARGET_SDK_TOO_HIGH = 3; + /** + * Package does not exist. + */ + public static final int PACKAGE_DOES_NOT_EXIST = 4; + + @State + public final int state; + public final int appTargetSdk; + public final int changeIdTargetSdk; + + private OverrideAllowedState(Parcel parcel) { + state = parcel.readInt(); + appTargetSdk = parcel.readInt(); + changeIdTargetSdk = parcel.readInt(); + } + + public OverrideAllowedState(@State int state, int appTargetSdk, int changeIdTargetSdk) { + this.state = state; + this.appTargetSdk = appTargetSdk; + this.changeIdTargetSdk = changeIdTargetSdk; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(state); + out.writeInt(appTargetSdk); + out.writeInt(changeIdTargetSdk); + } + + /** + * Enforces the policy for overriding compat changes. + * + * @param changeId the change id that was attempted to be overridden. + * @param packageName the package for which the attempt was made. + * @throws SecurityException if the policy forbids this operation. + */ + public void enforce(long changeId, String packageName) + throws SecurityException { + switch (state) { + case ALLOWED: + return; + case DISABLED_NOT_DEBUGGABLE: + throw new SecurityException( + "Cannot override a change on a non-debuggable app and user build."); + case DISABLED_NON_TARGET_SDK: + throw new SecurityException( + "Cannot override a default enabled/disabled change on a user build."); + case DISABLED_TARGET_SDK_TOO_HIGH: + throw new SecurityException(String.format( + "Cannot override %1$d for %2$s because the app's targetSdk (%3$d) is " + + "above the change's targetSdk threshold (%4$d)", + changeId, packageName, appTargetSdk, changeIdTargetSdk)); + case PACKAGE_DOES_NOT_EXIST: + throw new SecurityException(String.format( + "Cannot override %1$d for %2$s because the package does not exist, and " + + "the change is targetSdk gated.", + changeId, packageName)); + } + } + + public static final @NonNull + Parcelable.Creator<OverrideAllowedState> CREATOR = + new Parcelable.Creator<OverrideAllowedState>() { + public OverrideAllowedState createFromParcel(Parcel parcel) { + OverrideAllowedState info = new OverrideAllowedState(parcel); + return info; + } + + public OverrideAllowedState[] newArray(int size) { + return new OverrideAllowedState[size]; + } + }; + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof OverrideAllowedState)) { + return false; + } + OverrideAllowedState otherState = (OverrideAllowedState) obj; + return state == otherState.state + && appTargetSdk == otherState.appTargetSdk + && changeIdTargetSdk == otherState.changeIdTargetSdk; + } +} diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index f14145b35db7..fa823c4bf2f6 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -35,7 +35,6 @@ 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; @@ -205,7 +204,6 @@ 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()); @@ -218,35 +216,6 @@ 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 6d71c508bf1c..a42ba17c100e 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -451,7 +451,6 @@ <protected-broadcast android:name="android.intent.action.internal_sim_state_changed" /> <protected-broadcast android:name="android.intent.action.LOCKED_BOOT_COMPLETED" /> <protected-broadcast android:name="android.intent.action.PRECISE_CALL_STATE" /> - <protected-broadcast android:name="android.intent.action.PRECISE_DATA_CONNECTION_STATE_CHANGED" /> <protected-broadcast android:name="android.intent.action.SUBSCRIPTION_PHONE_STATE" /> <protected-broadcast android:name="android.intent.action.USER_INFO_CHANGED" /> <protected-broadcast android:name="android.intent.action.USER_UNLOCKED" /> 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/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java index ea00d6eff12e..c17beba2b9d1 100644 --- a/media/java/android/media/tv/TvTrackInfo.java +++ b/media/java/android/media/tv/TvTrackInfo.java @@ -61,6 +61,8 @@ public final class TvTrackInfo implements Parcelable { private final boolean mEncrypted; private final int mAudioChannelCount; private final int mAudioSampleRate; + private final boolean mAudioDescription; + private final boolean mHardOfHearing; private final int mVideoWidth; private final int mVideoHeight; private final float mVideoFrameRate; @@ -70,9 +72,9 @@ public final class TvTrackInfo implements Parcelable { private final Bundle mExtra; private TvTrackInfo(int type, String id, String language, CharSequence description, - boolean encrypted, int audioChannelCount, int audioSampleRate, int videoWidth, - int videoHeight, float videoFrameRate, float videoPixelAspectRatio, - byte videoActiveFormatDescription, Bundle extra) { + boolean encrypted, int audioChannelCount, int audioSampleRate, boolean audioDescription, + boolean hardOfHearing, int videoWidth, int videoHeight, float videoFrameRate, + float videoPixelAspectRatio, byte videoActiveFormatDescription, Bundle extra) { mType = type; mId = id; mLanguage = language; @@ -80,6 +82,8 @@ public final class TvTrackInfo implements Parcelable { mEncrypted = encrypted; mAudioChannelCount = audioChannelCount; mAudioSampleRate = audioSampleRate; + mAudioDescription = audioDescription; + mHardOfHearing = hardOfHearing; mVideoWidth = videoWidth; mVideoHeight = videoHeight; mVideoFrameRate = videoFrameRate; @@ -96,6 +100,8 @@ public final class TvTrackInfo implements Parcelable { mEncrypted = in.readInt() != 0; mAudioChannelCount = in.readInt(); mAudioSampleRate = in.readInt(); + mAudioDescription = in.readInt() != 0; + mHardOfHearing = in.readInt() != 0; mVideoWidth = in.readInt(); mVideoHeight = in.readInt(); mVideoFrameRate = in.readFloat(); @@ -172,6 +178,40 @@ public final class TvTrackInfo implements Parcelable { } /** + * Returns {@code true} if the track is an audio description intended for people with visual + * impairment, {@code false} otherwise. Valid only for {@link #TYPE_AUDIO} tracks. + * + * <p>For example of broadcast, audio description information may be referred to broadcast + * standard (e.g. ISO 639 Language Descriptor of ISO/IEC 13818-1, Supplementary Audio Language + * Descriptor, AC-3 Descriptor, Enhanced AC-3 Descriptor, AAC Descriptor of ETSI EN 300 468). + * + * @throws IllegalStateException if not called on an audio track + */ + public boolean isAudioDescription() { + if (mType != TYPE_AUDIO) { + throw new IllegalStateException("Not an audio track"); + } + return mAudioDescription; + } + + /** + * Returns {@code true} if the track is intended for people with hearing impairment, {@code + * false} otherwise. Valid only for {@link #TYPE_AUDIO} and {@link #TYPE_SUBTITLE} tracks. + * + * <p>For example of broadcast, hard of hearing information may be referred to broadcast + * standard (e.g. ISO 639 Language Descriptor of ISO/IEC 13818-1, Supplementary Audio Language + * Descriptor, AC-3 Descriptor, Enhanced AC-3 Descriptor, AAC Descriptor of ETSI EN 300 468). + * + * @throws IllegalStateException if not called on an audio track or a subtitle track + */ + public boolean isHardOfHearing() { + if (mType != TYPE_AUDIO && mType != TYPE_SUBTITLE) { + throw new IllegalStateException("Not an audio or a subtitle track"); + } + return mHardOfHearing; + } + + /** * Returns the width of the video, in the unit of pixels. Valid only for {@link #TYPE_VIDEO} * tracks. * @@ -266,6 +306,8 @@ public final class TvTrackInfo implements Parcelable { dest.writeInt(mEncrypted ? 1 : 0); dest.writeInt(mAudioChannelCount); dest.writeInt(mAudioSampleRate); + dest.writeInt(mAudioDescription ? 1 : 0); + dest.writeInt(mHardOfHearing ? 1 : 0); dest.writeInt(mVideoWidth); dest.writeInt(mVideoHeight); dest.writeFloat(mVideoFrameRate); @@ -296,7 +338,9 @@ public final class TvTrackInfo implements Parcelable { switch (mType) { case TYPE_AUDIO: return mAudioChannelCount == obj.mAudioChannelCount - && mAudioSampleRate == obj.mAudioSampleRate; + && mAudioSampleRate == obj.mAudioSampleRate + && mAudioDescription == obj.mAudioDescription + && mHardOfHearing == obj.mHardOfHearing; case TYPE_VIDEO: return mVideoWidth == obj.mVideoWidth @@ -304,6 +348,9 @@ public final class TvTrackInfo implements Parcelable { && mVideoFrameRate == obj.mVideoFrameRate && mVideoPixelAspectRatio == obj.mVideoPixelAspectRatio && mVideoActiveFormatDescription == obj.mVideoActiveFormatDescription; + + case TYPE_SUBTITLE: + return mHardOfHearing == obj.mHardOfHearing; } return true; @@ -338,6 +385,8 @@ public final class TvTrackInfo implements Parcelable { private boolean mEncrypted; private int mAudioChannelCount; private int mAudioSampleRate; + private boolean mAudioDescription; + private boolean mHardOfHearing; private int mVideoWidth; private int mVideoHeight; private float mVideoFrameRate; @@ -430,6 +479,48 @@ public final class TvTrackInfo implements Parcelable { } /** + * Sets the audio description attribute of the audio. Valid only for {@link #TYPE_AUDIO} + * tracks. + * + * <p>For example of broadcast, audio description information may be referred to broadcast + * standard (e.g. ISO 639 Language Descriptor of ISO/IEC 13818-1, Supplementary Audio + * Language Descriptor, AC-3 Descriptor, Enhanced AC-3 Descriptor, AAC Descriptor of ETSI EN + * 300 468). + * + * @param audioDescription The audio description attribute of the audio. + * @throws IllegalStateException if not called on an audio track + */ + @NonNull + public Builder setAudioDescription(boolean audioDescription) { + if (mType != TYPE_AUDIO) { + throw new IllegalStateException("Not an audio track"); + } + mAudioDescription = audioDescription; + return this; + } + + /** + * Sets the hard of hearing attribute of the track. Valid only for {@link #TYPE_AUDIO} and + * {@link #TYPE_SUBTITLE} tracks. + * + * <p>For example of broadcast, hard of hearing information may be referred to broadcast + * standard (e.g. ISO 639 Language Descriptor of ISO/IEC 13818-1, Supplementary Audio + * Language Descriptor, AC-3 Descriptor, Enhanced AC-3 Descriptor, AAC Descriptor of ETSI EN + * 300 468). + * + * @param hardOfHearing The hard of hearing attribute of the track. + * @throws IllegalStateException if not called on an audio track or a subtitle track + */ + @NonNull + public Builder setHardOfHearing(boolean hardOfHearing) { + if (mType != TYPE_AUDIO && mType != TYPE_SUBTITLE) { + throw new IllegalStateException("Not an audio track or a subtitle track"); + } + mHardOfHearing = hardOfHearing; + return this; + } + + /** * Sets the width of the video, in the unit of pixels. Valid only for {@link #TYPE_VIDEO} * tracks. * @@ -531,8 +622,9 @@ public final class TvTrackInfo implements Parcelable { */ public TvTrackInfo build() { return new TvTrackInfo(mType, mId, mLanguage, mDescription, mEncrypted, - mAudioChannelCount, mAudioSampleRate, mVideoWidth, mVideoHeight, - mVideoFrameRate, mVideoPixelAspectRatio, mVideoActiveFormatDescription, mExtra); + mAudioChannelCount, mAudioSampleRate, mAudioDescription, mHardOfHearing, + mVideoWidth, mVideoHeight, mVideoFrameRate, mVideoPixelAspectRatio, + mVideoActiveFormatDescription, mExtra); } } } diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java index 9e49826f70c3..c2ce84023869 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java @@ -262,10 +262,11 @@ public class DynamicSystemInstallationService extends Service return; } + stopForeground(true); mJustCancelledByUser = true; if (mInstallTask.cancel(false)) { - // Will cleanup and post status in onResult() + // Will stopSelf() in onResult() Log.d(TAG, "Cancel request filed successfully"); } else { Log.e(TAG, "Trying to cancel installation while it's already completed."); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java index 4700baae8fab..18d436ff7659 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java @@ -421,7 +421,7 @@ public class NotificationGuts extends FrameLayout { } /** Listener for animations executed in {@link #animateClose(int, int, boolean)}. */ - private static class AnimateCloseListener extends AnimatorListenerAdapter { + private class AnimateCloseListener extends AnimatorListenerAdapter { final View mView; private final GutsContent mGutsContent; @@ -433,8 +433,10 @@ public class NotificationGuts extends FrameLayout { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); - mView.setVisibility(View.GONE); - mGutsContent.onFinishedClosing(); + if (!isExposed()) { + mView.setVisibility(View.GONE); + mGutsContent.onFinishedClosing(); + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index 8f7671a5dd96..719ec3215d42 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -100,6 +100,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx protected String mKeyToRemoveOnGutsClosed; private StatusBar mStatusBar; + private Runnable mOpenRunnable; @Inject public NotificationGutsManager( @@ -343,6 +344,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx public void closeAndSaveGuts(boolean removeLeavebehinds, boolean force, boolean removeControls, int x, int y, boolean resetMenu) { if (mNotificationGutsExposed != null) { + mNotificationGutsExposed.removeCallbacks(mOpenRunnable); mNotificationGutsExposed.closeControls(removeLeavebehinds, removeControls, x, y, force); } if (resetMenu) { @@ -445,7 +447,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx // ensure that it's laid but not visible until actually laid out guts.setVisibility(View.INVISIBLE); // Post to ensure the the guts are properly laid out. - guts.post(new Runnable() { + mOpenRunnable = new Runnable() { @Override public void run() { if (row.getWindowToken() == null) { @@ -470,7 +472,8 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx mListContainer.onHeightChanged(row, true /* needsAnimation */); mGutsMenuItem = menuItem; } - }); + }; + guts.post(mOpenRunnable); return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt index f4635d1270a8..f7b8a2e29129 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt @@ -67,6 +67,9 @@ class KeyguardLiftController constructor( } private fun updateListeningState() { + if (pickupSensor == null) { + return + } val onKeyguard = keyguardUpdateMonitor.isKeyguardVisible && !statusBarStateController.isDozing diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 0c47d1468a7f..68ee8bbbb69b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -62,6 +62,8 @@ import com.android.systemui.statusbar.policy.KeyguardMonitorImpl; import java.io.PrintWriter; import java.util.ArrayList; +import androidx.annotation.VisibleForTesting; + /** * Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back * via {@link ViewMediatorCallback} to poke the wake lock and report that the keyguard is done, @@ -161,6 +163,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb private boolean mLastLockVisible; private OnDismissAction mAfterKeyguardGoneAction; + private Runnable mKeyguardGoneCancelAction; private final ArrayList<Runnable> mAfterKeyguardGoneRunnables = new ArrayList<>(); // Dismiss action to be launched when we stop dozing or the keyguard is gone. @@ -328,10 +331,20 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb return false; } - private void hideBouncer(boolean destroyView) { + @VisibleForTesting + void hideBouncer(boolean destroyView) { if (mBouncer == null) { return; } + if (mShowing) { + // If we were showing the bouncer and then aborting, we need to also clear out any + // potential actions unless we actually unlocked. + mAfterKeyguardGoneAction = null; + if (mKeyguardGoneCancelAction != null) { + mKeyguardGoneCancelAction.run(); + mKeyguardGoneCancelAction = null; + } + } mBouncer.hide(destroyView); cancelPendingWakeupAction(); } @@ -364,6 +377,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mBouncer.showWithDismissAction(r, cancelAction); } else { mAfterKeyguardGoneAction = r; + mKeyguardGoneCancelAction = cancelAction; mBouncer.show(false /* resetSecuritySelection */); } } @@ -671,6 +685,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mAfterKeyguardGoneAction.onDismiss(); mAfterKeyguardGoneAction = null; } + mKeyguardGoneCancelAction = null; for (int i = 0; i < mAfterKeyguardGoneRunnables.size(); i++) { mAfterKeyguardGoneRunnables.get(i).run(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java index 63f653b0b303..0da0e7647707 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java @@ -221,6 +221,31 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase { verify(mStatusBar, never()).animateKeyguardUnoccluding(); } + @Test + public void testHiding_cancelsGoneRunnable() { + OnDismissAction action = mock(OnDismissAction.class); + Runnable cancelAction = mock(Runnable.class); + mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction, + true /* afterKeyguardGone */); + + mStatusBarKeyguardViewManager.hideBouncer(true); + mStatusBarKeyguardViewManager.hide(0, 30); + verify(action, never()).onDismiss(); + verify(cancelAction).run(); + } + + @Test + public void testHiding_doesntCancelWhenShowing() { + OnDismissAction action = mock(OnDismissAction.class); + Runnable cancelAction = mock(Runnable.class); + mStatusBarKeyguardViewManager.dismissWithAction(action, cancelAction, + true /* afterKeyguardGone */); + + mStatusBarKeyguardViewManager.hide(0, 30); + verify(action).onDismiss(); + verify(cancelAction, never()).run(); + } + private class TestableStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager { public TestableStatusBarKeyguardViewManager(Context context, 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/jarjar-rules.txt b/packages/Tethering/jarjar-rules.txt index dd9eab74e851..d93531bac58e 100644 --- a/packages/Tethering/jarjar-rules.txt +++ b/packages/Tethering/jarjar-rules.txt @@ -13,3 +13,5 @@ rule com.android.internal.util.State* com.android.networkstack.tethering.util.St rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1 rule android.net.LocalLog* com.android.networkstack.tethering.LocalLog@1 + +rule android.net.shared.Inet4AddressUtils* com.android.networkstack.tethering.shared.Inet4AddressUtils@1 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/dhcp/DhcpServingParamsParcelExt.java b/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java index 1fe2328f1cdb..d6bc063210b3 100644 --- a/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java +++ b/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java @@ -20,11 +20,11 @@ import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH; import android.annotation.NonNull; import android.net.LinkAddress; - -import com.google.android.collect.Sets; +import android.util.ArraySet; import java.net.Inet4Address; import java.util.Collection; +import java.util.Collections; import java.util.Set; /** @@ -68,7 +68,7 @@ public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel { * but it must always be set explicitly. */ public DhcpServingParamsParcelExt setDefaultRouters(@NonNull Inet4Address... defaultRouters) { - return setDefaultRouters(Sets.newArraySet(defaultRouters)); + return setDefaultRouters(newArraySet(defaultRouters)); } /** @@ -96,7 +96,7 @@ public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel { * <p>This may be an empty list of servers, but it must always be set explicitly. */ public DhcpServingParamsParcelExt setDnsServers(@NonNull Inet4Address... dnsServers) { - return setDnsServers(Sets.newArraySet(dnsServers)); + return setDnsServers(newArraySet(dnsServers)); } /** @@ -126,7 +126,7 @@ public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel { * and do not need to be set here. */ public DhcpServingParamsParcelExt setExcludedAddrs(@NonNull Inet4Address... excludedAddrs) { - return setExcludedAddrs(Sets.newArraySet(excludedAddrs)); + return setExcludedAddrs(newArraySet(excludedAddrs)); } /** @@ -169,4 +169,10 @@ public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel { } return res; } + + private static ArraySet<Inet4Address> newArraySet(Inet4Address... addrs) { + ArraySet<Inet4Address> addrSet = new ArraySet<>(addrs.length); + Collections.addAll(addrSet, addrs); + return addrSet; + } } diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java index 8fde52040ecc..abfb33c7af9e 100644 --- a/packages/Tethering/src/android/net/ip/IpServer.java +++ b/packages/Tethering/src/android/net/ip/IpServer.java @@ -17,10 +17,12 @@ package android.net.ip; import static android.net.InetAddresses.parseNumericAddress; +import static android.net.RouteInfo.RTN_UNICAST; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.util.NetworkConstants.FF; import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; import static android.net.util.NetworkConstants.asByte; +import static android.net.util.TetheringMessageBase.BASE_IPSERVER; import android.net.ConnectivityManager; import android.net.INetd; @@ -46,11 +48,9 @@ import android.os.Message; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.util.Log; -import android.util.Slog; import android.util.SparseArray; import com.android.internal.util.MessageUtils; -import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; @@ -153,27 +153,26 @@ public class IpServer extends StateMachine { DhcpServerCallbacks cb); } - private static final int BASE_IFACE = Protocol.BASE_TETHERING + 100; // request from the user that it wants to tether - public static final int CMD_TETHER_REQUESTED = BASE_IFACE + 2; + public static final int CMD_TETHER_REQUESTED = BASE_IPSERVER + 1; // request from the user that it wants to untether - public static final int CMD_TETHER_UNREQUESTED = BASE_IFACE + 3; + public static final int CMD_TETHER_UNREQUESTED = BASE_IPSERVER + 2; // notification that this interface is down - public static final int CMD_INTERFACE_DOWN = BASE_IFACE + 4; + public static final int CMD_INTERFACE_DOWN = BASE_IPSERVER + 3; // notification from the master SM that it had trouble enabling IP Forwarding - public static final int CMD_IP_FORWARDING_ENABLE_ERROR = BASE_IFACE + 7; + public static final int CMD_IP_FORWARDING_ENABLE_ERROR = BASE_IPSERVER + 4; // notification from the master SM that it had trouble disabling IP Forwarding - public static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IFACE + 8; + public static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IPSERVER + 5; // notification from the master SM that it had trouble starting tethering - public static final int CMD_START_TETHERING_ERROR = BASE_IFACE + 9; + public static final int CMD_START_TETHERING_ERROR = BASE_IPSERVER + 6; // notification from the master SM that it had trouble stopping tethering - public static final int CMD_STOP_TETHERING_ERROR = BASE_IFACE + 10; + public static final int CMD_STOP_TETHERING_ERROR = BASE_IPSERVER + 7; // notification from the master SM that it had trouble setting the DNS forwarders - public static final int CMD_SET_DNS_FORWARDERS_ERROR = BASE_IFACE + 11; + public static final int CMD_SET_DNS_FORWARDERS_ERROR = BASE_IPSERVER + 8; // the upstream connection has changed - public static final int CMD_TETHER_CONNECTION_CHANGED = BASE_IFACE + 12; + public static final int CMD_TETHER_CONNECTION_CHANGED = BASE_IPSERVER + 9; // new IPv6 tethering parameters need to be processed - public static final int CMD_IPV6_TETHER_UPDATE = BASE_IFACE + 13; + public static final int CMD_IPV6_TETHER_UPDATE = BASE_IPSERVER + 10; private final State mInitialState; private final State mLocalHotspotState; @@ -486,7 +485,9 @@ public class IpServer extends StateMachine { } // Directly-connected route. - final RouteInfo route = new RouteInfo(linkAddr); + final IpPrefix ipv4Prefix = new IpPrefix(linkAddr.getAddress(), + linkAddr.getPrefixLength()); + final RouteInfo route = new RouteInfo(ipv4Prefix, null, null, RTN_UNICAST); if (enabled) { mLinkProperties.addLinkAddress(linkAddr); mLinkProperties.addRoute(route); @@ -1007,7 +1008,7 @@ public class IpServer extends StateMachine { String ifname, HashSet<IpPrefix> prefixes) { final ArrayList<RouteInfo> localRoutes = new ArrayList<RouteInfo>(); for (IpPrefix ipp : prefixes) { - localRoutes.add(new RouteInfo(ipp, null, ifname)); + localRoutes.add(new RouteInfo(ipp, null, ifname, RTN_UNICAST)); } return localRoutes; } @@ -1019,7 +1020,7 @@ public class IpServer extends StateMachine { try { return Inet6Address.getByAddress(null, dnsBytes, 0); } catch (UnknownHostException e) { - Slog.wtf(TAG, "Failed to construct Inet6Address from: " + localPrefix); + Log.wtf(TAG, "Failed to construct Inet6Address from: " + localPrefix); return null; } } diff --git a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java index 414741309ef0..bba61d72d8d6 100644 --- a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java +++ b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java @@ -22,14 +22,14 @@ import static android.system.OsConstants.AF_INET6; import static android.system.OsConstants.IPPROTO_ICMPV6; import static android.system.OsConstants.SOCK_RAW; import static android.system.OsConstants.SOL_SOCKET; -import static android.system.OsConstants.SO_BINDTODEVICE; import static android.system.OsConstants.SO_SNDTIMEO; import android.net.IpPrefix; import android.net.LinkAddress; -import android.net.NetworkUtils; import android.net.TrafficStats; import android.net.util.InterfaceParams; +import android.net.util.SocketUtils; +import android.net.util.TetheringUtils; import android.system.ErrnoException; import android.system.Os; import android.system.StructTimeval; @@ -38,8 +38,6 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.TrafficStatsConstants; -import libcore.io.IoBridge; - import java.io.FileDescriptor; import java.io.IOException; import java.net.Inet6Address; @@ -611,9 +609,8 @@ public class RouterAdvertisementDaemon { // Setting SNDTIMEO is purely for defensive purposes. Os.setsockoptTimeval( 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); + SocketUtils.bindSocketToInterface(mSocket, mInterface.name); + TetheringUtils.setupRaSocket(mSocket, mInterface.index); } catch (ErrnoException | IOException e) { Log.e(TAG, "Failed to create RA daemon socket: " + e); return false; @@ -627,7 +624,7 @@ public class RouterAdvertisementDaemon { private void closeSocket() { if (mSocket != null) { try { - IoBridge.closeAndSignalBlockedThreads(mSocket); + SocketUtils.closeSocket(mSocket); } catch (IOException ignored) { } } mSocket = null; diff --git a/packages/Tethering/src/android/net/util/TetheringMessageBase.java b/packages/Tethering/src/android/net/util/TetheringMessageBase.java new file mode 100644 index 000000000000..1b763ce920da --- /dev/null +++ b/packages/Tethering/src/android/net/util/TetheringMessageBase.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2020 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; + +/** + * This class defines Message.what base addresses for various state machine. + */ +public class TetheringMessageBase { + public static final int BASE_MASTER = 0; + public static final int BASE_IPSERVER = 100; + +} 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..fa543bdce735 --- /dev/null +++ b/packages/Tethering/src/android/net/util/TetheringUtils.java @@ -0,0 +1,49 @@ +/* + * 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; + + /** + * Read s as an unsigned 16-bit integer. + */ + public static int uint16(short s) { + return s & 0xffff; + } +} diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java index ba5d08dce4ca..7e685fbe97f1 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java @@ -38,7 +38,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; import android.net.util.SharedLog; -import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -48,7 +47,6 @@ import android.os.PersistableBundle; import android.os.ResultReceiver; import android.os.SystemClock; import android.os.SystemProperties; -import android.os.UserHandle; import android.provider.Settings; import android.telephony.CarrierConfigManager; import android.util.ArraySet; @@ -196,9 +194,9 @@ public class EntitlementManager { // till upstream change to cellular. if (mUsingCellularAsUpstream) { if (showProvisioningUi) { - runUiTetherProvisioning(type, config.subId); + runUiTetherProvisioning(type, config.activeDataSubId); } else { - runSilentTetherProvisioning(type, config.subId); + runSilentTetherProvisioning(type, config.activeDataSubId); } mNeedReRunProvisioningUi = false; } else { @@ -270,9 +268,9 @@ public class EntitlementManager { if (mCellularPermitted.indexOfKey(downstream) < 0) { if (mNeedReRunProvisioningUi) { mNeedReRunProvisioningUi = false; - runUiTetherProvisioning(downstream, config.subId); + runUiTetherProvisioning(downstream, config.activeDataSubId); } else { - runSilentTetherProvisioning(downstream, config.subId); + runSilentTetherProvisioning(downstream, config.activeDataSubId); } } } @@ -336,7 +334,8 @@ public class EntitlementManager { .getSystemService(Context.CARRIER_CONFIG_SERVICE); if (configManager == null) return null; - final PersistableBundle carrierConfig = configManager.getConfigForSubId(config.subId); + final PersistableBundle carrierConfig = configManager.getConfigForSubId( + config.activeDataSubId); if (CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfig)) { return carrierConfig; @@ -379,12 +378,9 @@ public class EntitlementManager { intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver); intent.putExtra(EXTRA_SUBID, subId); intent.setComponent(TETHER_SERVICE); - final long ident = Binder.clearCallingIdentity(); - try { - mContext.startServiceAsUser(intent, UserHandle.CURRENT); - } finally { - Binder.restoreCallingIdentity(ident); - } + // Only admin user can change tethering and SilentTetherProvisioning don't need to + // show UI, it is fine to always start setting's background service as system user. + mContext.startService(intent); } private void runUiTetherProvisioning(int type, int subId) { @@ -407,12 +403,9 @@ public class EntitlementManager { intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver); intent.putExtra(EXTRA_SUBID, subId); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - final long ident = Binder.clearCallingIdentity(); - try { - mContext.startActivityAsUser(intent, UserHandle.CURRENT); - } finally { - Binder.restoreCallingIdentity(ident); - } + // Only launch entitlement UI for system user. Entitlement UI should not appear for other + // user because only admin user is allowed to change tethering. + mContext.startActivity(intent); } // Not needed to check if this don't run on the handler thread because it's private. @@ -671,7 +664,7 @@ public class EntitlementManager { receiver.send(cacheValue, null); } else { ResultReceiver proxy = buildProxyReceiver(downstream, false/* notifyFail */, receiver); - runUiTetherProvisioning(downstream, config.subId, proxy); + runUiTetherProvisioning(downstream, config.activeDataSubId, proxy); } } } diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java index 93054140213d..66b9ade81019 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java @@ -29,6 +29,7 @@ import android.util.Log; import java.net.Inet6Address; import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; @@ -257,7 +258,7 @@ public class IPv6TetheringCoordinator { final LinkProperties lp = new LinkProperties(); final IpPrefix local48 = makeUniqueLocalPrefix(ulp, (short) 0, 48); - lp.addRoute(new RouteInfo(local48, null, null)); + lp.addRoute(new RouteInfo(local48, null, null, RouteInfo.RTN_UNICAST)); final IpPrefix local64 = makeUniqueLocalPrefix(ulp, subnetId, 64); // Because this is a locally-generated ULA, we don't have an upstream @@ -273,7 +274,13 @@ public class IPv6TetheringCoordinator { final byte[] bytes = Arrays.copyOf(in6addr, in6addr.length); bytes[7] = (byte) (subnetId >> 8); bytes[8] = (byte) subnetId; - return new IpPrefix(bytes, prefixlen); + final InetAddress addr; + try { + addr = InetAddress.getByAddress(bytes); + } catch (UnknownHostException e) { + throw new IllegalStateException("Invalid address length: " + bytes.length, e); + } + return new IpPrefix(addr, prefixlen); } // Generates a Unique Locally-assigned Prefix: diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java index 16734d83e3aa..38fa91e7387e 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java @@ -25,6 +25,7 @@ import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; import android.content.ContentResolver; import android.net.ITetheringStatsProvider; +import android.net.InetAddresses; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; @@ -33,7 +34,6 @@ import android.net.RouteInfo; import android.net.netlink.ConntrackMessage; import android.net.netlink.NetlinkConstants; import android.net.netlink.NetlinkSocket; -import android.net.util.IpUtils; import android.net.util.SharedLog; import android.os.Handler; import android.os.INetworkManagementService; @@ -477,9 +477,10 @@ public class OffloadController { if (!ri.hasGateway()) continue; final String gateway = ri.getGateway().getHostAddress(); - if (ri.isIPv4Default()) { + final InetAddress address = ri.getDestination().getAddress(); + if (ri.isDefaultRoute() && address instanceof Inet4Address) { v4gateway = gateway; - } else if (ri.isIPv6Default()) { + } else if (ri.isDefaultRoute() && address instanceof Inet6Address) { v6gateways.add(gateway); } } @@ -547,7 +548,10 @@ public class OffloadController { private static boolean shouldIgnoreDownstreamRoute(RouteInfo route) { // Ignore any link-local routes. - if (!route.getDestinationLinkAddress().isGlobalPreferred()) return true; + final IpPrefix destination = route.getDestination(); + final LinkAddress linkAddr = new LinkAddress(destination.getAddress(), + destination.getPrefixLength()); + if (!linkAddr.isGlobalPreferred()) return true; return false; } @@ -588,7 +592,7 @@ public class OffloadController { return; } - if (!IpUtils.isValidUdpOrTcpPort(srcPort)) { + if (!isValidUdpOrTcpPort(srcPort)) { mLog.e("Invalid src port: " + srcPort); return; } @@ -599,7 +603,7 @@ public class OffloadController { return; } - if (!IpUtils.isValidUdpOrTcpPort(dstPort)) { + if (!isValidUdpOrTcpPort(dstPort)) { mLog.e("Invalid dst port: " + dstPort); return; } @@ -628,7 +632,7 @@ public class OffloadController { private static Inet4Address parseIPv4Address(String addrString) { try { - final InetAddress ip = InetAddress.parseNumericAddress(addrString); + final InetAddress ip = InetAddresses.parseNumericAddress(addrString); // TODO: Consider other sanitization steps here, including perhaps: // not eql to 0.0.0.0 // not within 169.254.0.0/16 @@ -668,4 +672,8 @@ public class OffloadController { return 180; } } + + private static boolean isValidUdpOrTcpPort(int port) { + return port > 0 && port < 65536; + } } 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..4a8ef1f92754 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java @@ -16,7 +16,7 @@ package com.android.server.connectivity.tethering; -import static com.android.internal.util.BitUtils.uint16; +import static android.net.util.TetheringUtils.uint16; import android.hardware.tetheroffload.control.V1_0.IOffloadControl; import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback; @@ -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 f3b8cbc63757..2c8858eeafd3 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -37,6 +37,7 @@ import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL; import static android.net.ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE; import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE; +import static android.net.util.TetheringMessageBase.BASE_MASTER; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; @@ -106,7 +107,6 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.MessageUtils; -import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.networkstack.tethering.R; @@ -120,6 +120,8 @@ import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; /** * @@ -185,10 +187,10 @@ public class Tethering { private final TetheringDependencies mDeps; private final EntitlementManager mEntitlementMgr; private final Handler mHandler; - private final PhoneStateListener mPhoneStateListener; private final INetd mNetd; private final NetdCallback mNetdCallback; private final UserRestrictionActionListener mTetheringRestriction; + private final ActiveDataSubIdListener mActiveDataSubIdListener; private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID; // All the usage of mTetheringEventCallback should run in the same thread. private ITetheringEventCallback mTetheringEventCallback = null; @@ -252,26 +254,6 @@ public class Tethering { mEntitlementMgr.reevaluateSimCardProvisioning(mConfig); }); - mPhoneStateListener = new PhoneStateListener(mLooper) { - @Override - public void onActiveDataSubscriptionIdChanged(int subId) { - mLog.log("OBSERVED active data subscription change, from " + mActiveDataSubId - + " to " + subId); - if (subId == mActiveDataSubId) return; - - mActiveDataSubId = subId; - updateConfiguration(); - // To avoid launching unexpected provisioning checks, ignore re-provisioning when - // no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning() will be - // triggered again when CarrierConfig is loaded. - if (mEntitlementMgr.getCarrierConfig(mConfig) != null) { - mEntitlementMgr.reevaluateSimCardProvisioning(mConfig); - } else { - mLog.log("IGNORED reevaluate provisioning due to no carrier config loaded"); - } - } - }; - mStateReceiver = new StateReceiver(); mNetdCallback = new NetdCallback(); @@ -284,6 +266,8 @@ public class Tethering { final UserManager userManager = (UserManager) mContext.getSystemService( Context.USER_SERVICE); mTetheringRestriction = new UserRestrictionActionListener(userManager, this); + final TetheringThreadExecutor executor = new TetheringThreadExecutor(mHandler); + mActiveDataSubIdListener = new ActiveDataSubIdListener(executor); // Load tethering configuration. updateConfiguration(); @@ -294,8 +278,8 @@ public class Tethering { private void startStateMachineUpdaters(Handler handler) { mCarrierConfigChange.startListening(); - mContext.getSystemService(TelephonyManager.class).listen( - mPhoneStateListener, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); + mContext.getSystemService(TelephonyManager.class).listen(mActiveDataSubIdListener, + PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); IntentFilter filter = new IntentFilter(); filter.addAction(UsbManager.ACTION_USB_STATE); @@ -314,6 +298,43 @@ public class Tethering { } + private class TetheringThreadExecutor implements Executor { + private final Handler mTetherHandler; + TetheringThreadExecutor(Handler handler) { + mTetherHandler = handler; + } + @Override + public void execute(Runnable command) { + if (!mTetherHandler.post(command)) { + throw new RejectedExecutionException(mTetherHandler + " is shutting down"); + } + } + } + + private class ActiveDataSubIdListener extends PhoneStateListener { + ActiveDataSubIdListener(Executor executor) { + super(executor); + } + + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + mLog.log("OBSERVED active data subscription change, from " + mActiveDataSubId + + " to " + subId); + if (subId == mActiveDataSubId) return; + + mActiveDataSubId = subId; + updateConfiguration(); + // To avoid launching unexpected provisioning checks, ignore re-provisioning + // when no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning() + // ill be triggered again when CarrierConfig is loaded. + if (mEntitlementMgr.getCarrierConfig(mConfig) != null) { + mEntitlementMgr.reevaluateSimCardProvisioning(mConfig); + } else { + mLog.log("IGNORED reevaluate provisioning, no carrier config loaded"); + } + } + } + private WifiManager getWifiManager() { return (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); } @@ -326,8 +347,7 @@ public class Tethering { } private void maybeDunSettingChanged() { - final boolean isDunRequired = TetheringConfiguration.checkDunRequired( - mContext, mActiveDataSubId); + final boolean isDunRequired = TetheringConfiguration.checkDunRequired(mContext); if (isDunRequired == mConfig.isDunRequired) return; updateConfiguration(); } @@ -1162,7 +1182,6 @@ public class Tethering { } class TetherMasterSM extends StateMachine { - private static final int BASE_MASTER = Protocol.BASE_TETHERING; // an interface SM has requested Tethering/Local Hotspot static final int EVENT_IFACE_SERVING_STATE_ACTIVE = BASE_MASTER + 1; // an interface SM has unrequested Tethering/Local Hotspot @@ -1179,7 +1198,6 @@ public class Tethering { static final int EVENT_IFACE_UPDATE_LINKPROPERTIES = BASE_MASTER + 7; // Events from EntitlementManager to choose upstream again. static final int EVENT_UPSTREAM_PERMISSION_CHANGED = BASE_MASTER + 8; - private final State mInitialState; private final State mTetherModeAliveState; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java index 0ab4d634e84d..490614b03149 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java @@ -100,13 +100,13 @@ public class TetheringConfiguration { public final String provisioningAppNoUi; public final int provisioningCheckPeriod; - public final int subId; + public final int activeDataSubId; public TetheringConfiguration(Context ctx, SharedLog log, int id) { final SharedLog configLog = log.forSubComponent("config"); - subId = id; - Resources res = getResources(ctx, subId); + activeDataSubId = id; + Resources res = getResources(ctx, activeDataSubId); tetherableUsbRegexs = getResourceStringArray(res, config_tether_usb_regexs); // TODO: Evaluate deleting this altogether now that Wi-Fi always passes @@ -116,7 +116,7 @@ public class TetheringConfiguration { tetherableWifiP2pRegexs = getResourceStringArray(res, config_tether_wifi_p2p_regexs); tetherableBluetoothRegexs = getResourceStringArray(res, config_tether_bluetooth_regexs); - isDunRequired = checkDunRequired(ctx, subId); + isDunRequired = checkDunRequired(ctx); chooseUpstreamAutomatically = getResourceBoolean(res, config_tether_upstream_automatic); preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired); @@ -166,8 +166,8 @@ public class TetheringConfiguration { /** Does the dumping.*/ public void dump(PrintWriter pw) { - pw.print("subId: "); - pw.println(subId); + pw.print("activeDataSubId: "); + pw.println(activeDataSubId); dumpStringArray(pw, "tetherableUsbRegexs", tetherableUsbRegexs); dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs); @@ -196,7 +196,7 @@ public class TetheringConfiguration { /** Returns the string representation of this object.*/ public String toString() { final StringJoiner sj = new StringJoiner(" "); - sj.add(String.format("subId:%d", subId)); + sj.add(String.format("activeDataSubId:%d", activeDataSubId)); sj.add(String.format("tetherableUsbRegexs:%s", makeString(tetherableUsbRegexs))); sj.add(String.format("tetherableWifiRegexs:%s", makeString(tetherableWifiRegexs))); sj.add(String.format("tetherableWifiP2pRegexs:%s", makeString(tetherableWifiP2pRegexs))); @@ -250,9 +250,11 @@ public class TetheringConfiguration { } /** Check whether dun is required. */ - public static boolean checkDunRequired(Context ctx, int id) { + public static boolean checkDunRequired(Context ctx) { final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE); - return (tm != null) ? tm.isTetheringApnRequired(id) : false; + // TelephonyManager would uses the active data subscription, which should be the one used + // by tethering. + return (tm != null) ? tm.isTetheringApnRequired() : false; } private static Collection<Integer> getUpstreamIfaceTypes(Resources res, boolean dunRequired) { @@ -391,7 +393,7 @@ public class TetheringConfiguration { */ public TetheringConfigurationParcel toStableParcelable() { final TetheringConfigurationParcel parcel = new TetheringConfigurationParcel(); - parcel.subId = subId; + parcel.subId = activeDataSubId; parcel.tetherableUsbRegexs = tetherableUsbRegexs; parcel.tetherableWifiRegexs = tetherableWifiRegexs; parcel.tetherableBluetoothRegexs = tetherableBluetoothRegexs; 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..775484eabfa3 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java @@ -21,6 +21,7 @@ import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERM import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_UNSUPPORTED; +import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR; import android.app.Service; import android.content.Context; @@ -84,6 +85,7 @@ public class TetheringService extends Service { */ @VisibleForTesting public Tethering makeTethering(TetheringDependencies deps) { + System.loadLibrary("tetherutilsjni"); return new Tethering(deps); } @@ -339,7 +341,10 @@ public class TetheringService extends Service { service.makeDhcpServer(ifName, params, cb); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + Log.e(TAG, "Fail to make dhcp server"); + try { + cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null); + } catch (RemoteException re) { } } } }; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java index dc38c49a0c12..22150f623a35 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java @@ -328,13 +328,6 @@ public class UpstreamNetworkMonitor { network, newNc)); } - // Log changes in upstream network signal strength, if available. - if (network.equals(mTetheringUpstreamNetwork) && newNc.hasSignalStrength()) { - final int newSignal = newNc.getSignalStrength(); - final String prevSignal = getSignalStrength(prev.networkCapabilities); - mLog.logf("upstream network signal strength: %s -> %s", prevSignal, newSignal); - } - mNetworkMap.put(network, new UpstreamNetworkState( prev.linkProperties, newNc, network)); // TODO: If sufficient information is available to select a more @@ -557,11 +550,6 @@ public class UpstreamNetworkMonitor { return prefixSet; } - private static String getSignalStrength(NetworkCapabilities nc) { - if (nc == null || !nc.hasSignalStrength()) return "unknown"; - return Integer.toString(nc.getSignalStrength()); - } - private static boolean isCellular(UpstreamNetworkState ns) { return (ns != null) && isCellular(ns.networkCapabilities); } 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/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java b/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java index e01ac7f08c2f..e8add9830b5f 100644 --- a/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java +++ b/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java @@ -18,8 +18,6 @@ package android.net.dhcp; import static android.net.InetAddresses.parseNumericAddress; -import static com.google.android.collect.Sets.newHashSet; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -34,6 +32,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.net.Inet4Address; +import java.util.Arrays; +import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -47,9 +47,10 @@ public class DhcpServingParamsParcelExtTest { private static final int TEST_LEASE_TIME_SECS = 120; private static final int TEST_MTU = 1000; private static final Set<Inet4Address> TEST_ADDRESS_SET = - newHashSet(inet4Addr("192.168.1.123"), inet4Addr("192.168.1.124")); + new HashSet<Inet4Address>(Arrays.asList( + new Inet4Address[] {inet4Addr("192.168.1.123"), inet4Addr("192.168.1.124")})); private static final Set<Integer> TEST_ADDRESS_SET_PARCELED = - newHashSet(0xc0a8017b, 0xc0a8017c); + new HashSet<Integer>(Arrays.asList(new Integer[] {0xc0a8017b, 0xc0a8017c})); private DhcpServingParamsParcelExt mParcel; diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 4358cd6966f1..fd2f708aea30 100644 --- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -510,8 +510,10 @@ public class IpServerTest { } assertNotNull("missing IPv4 address", addr4); + final IpPrefix destination = new IpPrefix(addr4.getAddress(), addr4.getPrefixLength()); // Assert the presence of the associated directly connected route. - final RouteInfo directlyConnected = new RouteInfo(addr4, null, lp.getInterfaceName()); + final RouteInfo directlyConnected = new RouteInfo(destination, null, lp.getInterfaceName(), + RouteInfo.RTN_UNICAST); assertTrue("missing directly connected route: '" + directlyConnected.toString() + "'", lp.getRoutes().contains(directlyConnected)); } diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java index 8574f5401496..7886ca6c132d 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java @@ -21,6 +21,7 @@ import static android.net.NetworkStats.STATS_PER_IFACE; import static android.net.NetworkStats.STATS_PER_UID; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; +import static android.net.RouteInfo.RTN_UNICAST; import static android.net.TrafficStats.UID_TETHERING; import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; @@ -269,7 +270,7 @@ public class OffloadControllerTest { final String ipv4Addr = "192.0.2.5"; final String linkAddr = ipv4Addr + "/24"; lp.addLinkAddress(new LinkAddress(linkAddr)); - lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"))); + lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, null, RTN_UNICAST)); offload.setUpstreamLinkProperties(lp); // IPv4 prefixes and addresses on the upstream are simply left as whole // prefixes (already passed in from UpstreamNetworkMonitor code). If a @@ -285,7 +286,7 @@ public class OffloadControllerTest { inOrder.verifyNoMoreInteractions(); final String ipv4Gateway = "192.0.2.1"; - lp.addRoute(new RouteInfo(InetAddress.getByName(ipv4Gateway))); + lp.addRoute(new RouteInfo(null, InetAddress.getByName(ipv4Gateway), null, RTN_UNICAST)); offload.setUpstreamLinkProperties(lp); // No change in local addresses means no call to setLocalPrefixes(). inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); @@ -296,7 +297,7 @@ public class OffloadControllerTest { inOrder.verifyNoMoreInteractions(); final String ipv6Gw1 = "fe80::cafe"; - lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw1))); + lp.addRoute(new RouteInfo(null, InetAddress.getByName(ipv6Gw1), null, RTN_UNICAST)); offload.setUpstreamLinkProperties(lp); // No change in local addresses means no call to setLocalPrefixes(). inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); @@ -310,7 +311,7 @@ public class OffloadControllerTest { inOrder.verifyNoMoreInteractions(); final String ipv6Gw2 = "fe80::d00d"; - lp.addRoute(new RouteInfo(InetAddress.getByName(ipv6Gw2))); + lp.addRoute(new RouteInfo(null, InetAddress.getByName(ipv6Gw2), null, RTN_UNICAST)); offload.setUpstreamLinkProperties(lp); // No change in local addresses means no call to setLocalPrefixes(). inOrder.verify(mHardware, never()).setLocalPrefixes(mStringArrayCaptor.capture()); @@ -327,8 +328,10 @@ public class OffloadControllerTest { final LinkProperties stacked = new LinkProperties(); stacked.setInterfaceName("stacked"); stacked.addLinkAddress(new LinkAddress("192.0.2.129/25")); - stacked.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254"))); - stacked.addRoute(new RouteInfo(InetAddress.getByName("fe80::bad:f00"))); + stacked.addRoute(new RouteInfo(null, InetAddress.getByName("192.0.2.254"), null, + RTN_UNICAST)); + stacked.addRoute(new RouteInfo(null, InetAddress.getByName("fe80::bad:f00"), null, + RTN_UNICAST)); assertTrue(lp.addStackedLink(stacked)); offload.setUpstreamLinkProperties(lp); // No change in local addresses means no call to setLocalPrefixes(). @@ -348,7 +351,7 @@ public class OffloadControllerTest { // removed from "local prefixes" and /128s added for the upstream IPv6 // addresses. This is not yet implemented, and for now we simply // expect to see these /128s. - lp.addRoute(new RouteInfo(new IpPrefix("2001:db8::/64"))); + lp.addRoute(new RouteInfo(new IpPrefix("2001:db8::/64"), null, null, RTN_UNICAST)); // "2001:db8::/64" plus "assigned" ASCII in hex lp.addLinkAddress(new LinkAddress("2001:db8::6173:7369:676e:6564/64")); // "2001:db8::/64" plus "random" ASCII in hex @@ -574,13 +577,15 @@ public class OffloadControllerTest { final LinkProperties usbLinkProperties = new LinkProperties(); usbLinkProperties.setInterfaceName(RNDIS0); usbLinkProperties.addLinkAddress(new LinkAddress("192.168.42.1/24")); - usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(USB_PREFIX))); + usbLinkProperties.addRoute( + new RouteInfo(new IpPrefix(USB_PREFIX), null, null, RTN_UNICAST)); offload.notifyDownstreamLinkProperties(usbLinkProperties); inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, USB_PREFIX); inOrder.verifyNoMoreInteractions(); // [2] Routes for IPv6 link-local prefixes should never be added. - usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_LINKLOCAL))); + usbLinkProperties.addRoute( + new RouteInfo(new IpPrefix(IPV6_LINKLOCAL), null, null, RTN_UNICAST)); offload.notifyDownstreamLinkProperties(usbLinkProperties); inOrder.verify(mHardware, never()).addDownstreamPrefix(eq(RNDIS0), anyString()); inOrder.verifyNoMoreInteractions(); @@ -588,7 +593,8 @@ public class OffloadControllerTest { // [3] Add an IPv6 prefix for good measure. Only new offload-able // prefixes should be passed to the HAL. usbLinkProperties.addLinkAddress(new LinkAddress("2001:db8::1/64")); - usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX))); + usbLinkProperties.addRoute( + new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX), null, null, RTN_UNICAST)); offload.notifyDownstreamLinkProperties(usbLinkProperties); inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, IPV6_DOC_PREFIX); inOrder.verifyNoMoreInteractions(); @@ -601,8 +607,10 @@ public class OffloadControllerTest { // [5] Differences in local routes are converted into addDownstream() // and removeDownstream() invocations accordingly. - usbLinkProperties.removeRoute(new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX), null, RNDIS0)); - usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_DISCARD_PREFIX))); + usbLinkProperties.removeRoute( + new RouteInfo(new IpPrefix(IPV6_DOC_PREFIX), null, RNDIS0, RTN_UNICAST)); + usbLinkProperties.addRoute( + new RouteInfo(new IpPrefix(IPV6_DISCARD_PREFIX), null, null, RTN_UNICAST)); offload.notifyDownstreamLinkProperties(usbLinkProperties); inOrder.verify(mHardware, times(1)).removeDownstreamPrefix(RNDIS0, IPV6_DOC_PREFIX); inOrder.verify(mHardware, times(1)).addDownstreamPrefix(RNDIS0, IPV6_DISCARD_PREFIX); @@ -680,19 +688,23 @@ public class OffloadControllerTest { final LinkProperties usbLinkProperties = new LinkProperties(); usbLinkProperties.setInterfaceName(RNDIS0); usbLinkProperties.addLinkAddress(new LinkAddress("192.168.42.1/24")); - usbLinkProperties.addRoute(new RouteInfo(new IpPrefix(USB_PREFIX))); + usbLinkProperties.addRoute( + new RouteInfo(new IpPrefix(USB_PREFIX), null, null, RTN_UNICAST)); offload.notifyDownstreamLinkProperties(usbLinkProperties); final LinkProperties wifiLinkProperties = new LinkProperties(); wifiLinkProperties.setInterfaceName(WLAN0); wifiLinkProperties.addLinkAddress(new LinkAddress("192.168.43.1/24")); - wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix(WIFI_PREFIX))); - wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix(IPV6_LINKLOCAL))); + wifiLinkProperties.addRoute( + new RouteInfo(new IpPrefix(WIFI_PREFIX), null, null, RTN_UNICAST)); + wifiLinkProperties.addRoute( + new RouteInfo(new IpPrefix(IPV6_LINKLOCAL), null, null, RTN_UNICAST)); // Use a benchmark prefix (RFC 5180 + erratum), since the documentation // prefix is included in the excluded prefix list. wifiLinkProperties.addLinkAddress(new LinkAddress("2001:2::1/64")); wifiLinkProperties.addLinkAddress(new LinkAddress("2001:2::2/64")); - wifiLinkProperties.addRoute(new RouteInfo(new IpPrefix("2001:2::/64"))); + wifiLinkProperties.addRoute( + new RouteInfo(new IpPrefix("2001:2::/64"), null, null, RTN_UNICAST)); offload.notifyDownstreamLinkProperties(wifiLinkProperties); offload.removeDownstreamInterface(RNDIS0); diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java index 30bff3560955..7799da4b94a7 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java @@ -34,7 +34,6 @@ import static com.android.internal.R.array.config_tether_wifi_regexs; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.when; import android.content.ContentResolver; @@ -145,7 +144,7 @@ public class TetheringConfigurationTest { @Test public void testDunFromTelephonyManagerMeansDun() { - when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(true); + when(mTelephonyManager.isTetheringApnRequired()).thenReturn(true); final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI); final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration( @@ -169,7 +168,7 @@ public class TetheringConfigurationTest { @Test public void testDunNotRequiredFromTelephonyManagerMeansNoDun() { - when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false); + when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI); final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration( @@ -212,7 +211,7 @@ public class TetheringConfigurationTest { @Test public void testNoDefinedUpstreamTypesAddsEthernet() { when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[]{}); - when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false); + when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); @@ -235,7 +234,7 @@ public class TetheringConfigurationTest { public void testDefinedUpstreamTypesSansEthernetAddsEthernet() { when(mResources.getIntArray(config_tether_upstream_types)).thenReturn( new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI}); - when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false); + when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); @@ -253,7 +252,7 @@ public class TetheringConfigurationTest { public void testDefinedUpstreamTypesWithEthernetDoesNotAddEthernet() { when(mResources.getIntArray(config_tether_upstream_types)) .thenReturn(new int[]{TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_HIPRI}); - when(mTelephonyManager.isTetheringApnRequired(anyInt())).thenReturn(false); + when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( mMockContext, mLog, INVALID_SUBSCRIPTION_ID); diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index 0bc8c7944615..809f0e994737 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -28,6 +28,7 @@ import static android.net.ConnectivityManager.TETHERING_WIFI; import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; +import static android.net.RouteInfo.RTN_UNICAST; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; @@ -72,6 +73,7 @@ import android.net.INetd; import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.ITetheringEventCallback; +import android.net.InetAddresses; import android.net.InterfaceConfiguration; import android.net.IpPrefix; import android.net.LinkAddress; @@ -81,7 +83,6 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkRequest; -import android.net.NetworkUtils; import android.net.RouteInfo; import android.net.TetherStatesParcel; import android.net.TetheringConfigurationParcel; @@ -365,23 +366,26 @@ public class TetheringTest { if (withIPv4) { prop.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), - NetworkUtils.numericToInetAddress("10.0.0.1"), TEST_MOBILE_IFNAME)); + InetAddresses.parseNumericAddress("10.0.0.1"), + TEST_MOBILE_IFNAME, RTN_UNICAST)); } if (withIPv6) { - prop.addDnsServer(NetworkUtils.numericToInetAddress("2001:db8::2")); + prop.addDnsServer(InetAddresses.parseNumericAddress("2001:db8::2")); prop.addLinkAddress( - new LinkAddress(NetworkUtils.numericToInetAddress("2001:db8::"), + new LinkAddress(InetAddresses.parseNumericAddress("2001:db8::"), NetworkConstants.RFC7421_PREFIX_LENGTH)); prop.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), - NetworkUtils.numericToInetAddress("2001:db8::1"), TEST_MOBILE_IFNAME)); + InetAddresses.parseNumericAddress("2001:db8::1"), + TEST_MOBILE_IFNAME, RTN_UNICAST)); } if (with464xlat) { final LinkProperties stackedLink = new LinkProperties(); stackedLink.setInterfaceName(TEST_XLAT_MOBILE_IFNAME); stackedLink.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), - NetworkUtils.numericToInetAddress("192.0.0.1"), TEST_XLAT_MOBILE_IFNAME)); + InetAddresses.parseNumericAddress("192.0.0.1"), + TEST_XLAT_MOBILE_IFNAME, RTN_UNICAST)); prop.addStackedLink(stackedLink); } @@ -1210,12 +1214,12 @@ public class TetheringTest { @Test public void testMultiSimAware() throws Exception { final TetheringConfiguration initailConfig = mTethering.getTetheringConfiguration(); - assertEquals(INVALID_SUBSCRIPTION_ID, initailConfig.subId); + assertEquals(INVALID_SUBSCRIPTION_ID, initailConfig.activeDataSubId); final int fakeSubId = 1234; mPhoneStateListener.onActiveDataSubscriptionIdChanged(fakeSubId); final TetheringConfiguration newConfig = mTethering.getTetheringConfiguration(); - assertEquals(fakeSubId, newConfig.subId); + assertEquals(fakeSubId, newConfig.activeDataSubId); } private void workingWifiP2pGroupOwner( diff --git a/services/TEST_MAPPING b/services/TEST_MAPPING deleted file mode 100644 index 5652ab1b88b9..000000000000 --- a/services/TEST_MAPPING +++ /dev/null @@ -1,48 +0,0 @@ -{ - "presubmit": [ - { - "name": "FrameworksCoreTests", - "options": [ - { - "include-annotation": "android.platform.test.annotations.Presubmit" - }, - { - "exclude-annotation": "androidx.test.filters.FlakyTest" - } - ] - }, - { - "name": "FrameworksServicesTests", - "options": [ - { - "include-annotation": "android.platform.test.annotations.Presubmit" - }, - { - "exclude-annotation": "androidx.test.filters.FlakyTest" - } - ] - }, - { - "name": "FrameworksMockingCoreTests", - "options": [ - { - "include-annotation": "android.platform.test.annotations.Presubmit" - }, - { - "exclude-annotation": "androidx.test.filters.FlakyTest" - } - ] - }, - { - "name": "WmTests", - "options": [ - { - "include-annotation": "android.platform.test.annotations.Presubmit" - }, - { - "exclude-annotation": "androidx.test.filters.FlakyTest" - } - ] - } - ] -} diff --git a/services/core/Android.bp b/services/core/Android.bp index cbd095b3a045..4c569efe4c0a 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -27,8 +27,8 @@ java_library_static { "android.hardware.light-V2.0-java", "android.hardware.power-V1.0-java", "android.hardware.tv.cec-V1.0-java", + "android.hardware.vibrator-java", "app-compat-annotations", - "vintf-vibrator-java", "framework-tethering", ], diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index bb78aceb3b5f..49cfa7b6de6d 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3022,25 +3022,9 @@ public class ConnectivityService extends IConnectivityManager.Stub if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { if (VDBG) log("NetworkFactory connected"); // Finish setting up the full connection - mNetworkFactoryInfos.get(msg.replyTo).asyncChannel.sendMessage( - AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); - // A network factory has connected. Send it all current NetworkRequests. - for (NetworkRequestInfo nri : mNetworkRequests.values()) { - if (nri.request.isListen()) continue; - ensureRunningOnConnectivityServiceThread(); - NetworkAgentInfo nai = nri.mSatisfier; - final int score; - final int serial; - if (nai != null) { - score = nai.getCurrentScore(); - serial = nai.factorySerialNumber; - } else { - score = 0; - serial = NetworkFactory.SerialNumber.NONE; - } - ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, serial, - nri.request); - } + NetworkFactoryInfo nfi = mNetworkFactoryInfos.get(msg.replyTo); + nfi.completeConnection(); + sendAllRequestsToFactory(nfi); } else { loge("Error connecting NetworkFactory"); mNetworkFactoryInfos.remove(msg.obj); @@ -3423,8 +3407,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST, - nri.request); + nfi.cancelRequest(nri.request); } } else { // listens don't have a singular affectedNetwork. Check all networks to see @@ -4920,16 +4903,33 @@ public class ConnectivityService extends IConnectivityManager.Stub private static class NetworkFactoryInfo { public final String name; public final Messenger messenger; - public final AsyncChannel asyncChannel; + private final AsyncChannel mAsyncChannel; public final int factorySerialNumber; NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel, int factorySerialNumber) { this.name = name; this.messenger = messenger; - this.asyncChannel = asyncChannel; + this.mAsyncChannel = asyncChannel; this.factorySerialNumber = factorySerialNumber; } + + void requestNetwork(NetworkRequest request, int score, int servingSerialNumber) { + mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, + servingSerialNumber, request); + } + + void cancelRequest(NetworkRequest request) { + mAsyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST, request); + } + + void connect(Context context, Handler handler) { + mAsyncChannel.connect(context, handler, messenger); + } + + void completeConnection() { + mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); + } } private void ensureNetworkRequestHasType(NetworkRequest request) { @@ -5318,7 +5318,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) { if (DBG) log("Got NetworkFactory Messenger for " + nfi.name); mNetworkFactoryInfos.put(nfi.messenger, nfi); - nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger); + nfi.connect(mContext, mTrackerHandler); } @Override @@ -5954,8 +5954,26 @@ public class ConnectivityService extends IConnectivityManager.Stub log("sending new Min Network Score(" + score + "): " + networkRequest.toString()); } for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, - serial, networkRequest); + nfi.requestNetwork(networkRequest, score, serial); + } + } + + /** Sends all current NetworkRequests to the specified factory. */ + private void sendAllRequestsToFactory(NetworkFactoryInfo nfi) { + ensureRunningOnConnectivityServiceThread(); + for (NetworkRequestInfo nri : mNetworkRequests.values()) { + if (nri.request.isListen()) continue; + NetworkAgentInfo nai = nri.mSatisfier; + final int score; + final int serial; + if (nai != null) { + score = nai.getCurrentScore(); + serial = nai.factorySerialNumber; + } else { + score = 0; + serial = NetworkFactory.SerialNumber.NONE; + } + nfi.requestNetwork(nri.request, score, serial); } } diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java index fe154ed8d396..9b1326bc88d7 100644 --- a/services/core/java/com/android/server/MmsServiceBroker.java +++ b/services/core/java/com/android/server/MmsServiceBroker.java @@ -16,6 +16,8 @@ package com.android.server; +import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; + import android.Manifest; import android.app.AppOpsManager; import android.app.PendingIntent; @@ -37,6 +39,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.service.carrier.CarrierMessagingService; import android.telephony.SmsManager; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Slog; @@ -512,11 +515,11 @@ public class MmsServiceBroker extends SystemService { // Grant permission for the carrier app. Intent intent = new Intent(action); - TelephonyManager telephonyManager = - (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); - List<String> carrierPackages = - telephonyManager.getCarrierPackageNamesForIntentAndPhone( - intent, SubscriptionManager.getPhoneId(subId)); + TelephonyManager telephonyManager = (TelephonyManager) + mContext.getSystemService(Context.TELEPHONY_SERVICE); + List<String> carrierPackages = telephonyManager + .getCarrierPackageNamesForIntentAndPhone( + intent, getPhoneIdFromSubId(subId)); if (carrierPackages != null && carrierPackages.size() == 1) { LocalServices.getService(UriGrantsManagerInternal.class) .grantUriPermissionFromIntent(callingUid, carrierPackages.get(0), @@ -528,4 +531,13 @@ public class MmsServiceBroker extends SystemService { return contentUri; } } + + private int getPhoneIdFromSubId(int subId) { + SubscriptionManager subManager = (SubscriptionManager) + mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); + if (subManager == null) return INVALID_SIM_SLOT_INDEX; + SubscriptionInfo info = subManager.getActiveSubscriptionInfo(subId); + if (info == null) return INVALID_SIM_SLOT_INDEX; + return info.getSimSlotIndex(); + } } 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..6a4ef4cd12dd 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -16,6 +16,7 @@ package com.android.server; +import static android.telephony.SubscriptionManager.INVALID_SIM_SLOT_INDEX; import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED; import static android.telephony.TelephonyRegistryManager.SIM_ACTIVATION_TYPE_DATA; import static android.telephony.TelephonyRegistryManager.SIM_ACTIVATION_TYPE_VOICE; @@ -57,6 +58,7 @@ import android.telephony.PreciseDisconnectCause; import android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.SignalStrength; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; @@ -95,7 +97,7 @@ import java.util.NoSuchElementException; * and 15973975 by saving the phoneId of the registrant and then using the * phoneId when deciding to to make a callback. This is necessary because * a subId changes from to a dummy value when a SIM is removed and thus won't - * compare properly. Because SubscriptionManager.getPhoneId(int subId) handles + * compare properly. Because getPhoneIdFromSubId(int subId) handles * the dummy value conversion we properly do the callbacks. * * Eventually we may want to remove the notion of dummy value but for now this @@ -128,7 +130,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - int phoneId = SubscriptionManager.INVALID_PHONE_INDEX; + int phoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; boolean matchPhoneStateListenerEvent(int events) { return (callback != null) && ((events & this.events) != 0); @@ -226,7 +228,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private int mDefaultSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - private int mDefaultPhoneId = SubscriptionManager.INVALID_PHONE_INDEX; + private int mDefaultPhoneId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; private int[] mRingingCallState; @@ -355,7 +357,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { SubscriptionManager.getDefaultSubscriptionId()); int newDefaultPhoneId = intent.getIntExtra( SubscriptionManager.EXTRA_SLOT_INDEX, - SubscriptionManager.getPhoneId(newDefaultSubId)); + getPhoneIdFromSubId(newDefaultSubId)); if (DBG) { log("onReceive:current mDefaultSubId=" + mDefaultSubId + " current mDefaultPhoneId=" + mDefaultPhoneId @@ -751,7 +753,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return; } - int phoneId = SubscriptionManager.getPhoneId(subId); + int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { // register IBinder b = callback.asBinder(); @@ -786,9 +788,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { r.callback.onServiceStateChanged(rawSs); } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) { - r.callback.onServiceStateChanged(rawSs.sanitizeLocationInfo(false)); + r.callback.onServiceStateChanged( + rawSs.createLocationInfoSanitizedCopy(false)); } else { - r.callback.onServiceStateChanged(rawSs.sanitizeLocationInfo(true)); + r.callback.onServiceStateChanged( + rawSs.createLocationInfoSanitizedCopy(true)); } } catch (RemoteException ex) { remove(r.binder); @@ -1077,7 +1081,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // Called only by Telecomm to communicate call state across different phone accounts. So // there is no need to add a valid subId or slotId. broadcastCallStateChanged(state, phoneNumber, - SubscriptionManager.INVALID_PHONE_INDEX, + SubscriptionManager.INVALID_SIM_SLOT_INDEX, SubscriptionManager.INVALID_SUBSCRIPTION_ID); } @@ -1144,9 +1148,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (checkFineLocationAccess(r, Build.VERSION_CODES.Q)) { stateToSend = new ServiceState(state); } else if (checkCoarseLocationAccess(r, Build.VERSION_CODES.Q)) { - stateToSend = state.sanitizeLocationInfo(false); + stateToSend = state.createLocationInfoSanitizedCopy(false); } else { - stateToSend = state.sanitizeLocationInfo(true); + stateToSend = state.createLocationInfoSanitizedCopy(true); } if (DBG) { log("notifyServiceStateForSubscriber: callback.onSSC r=" + r @@ -1301,7 +1305,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { synchronized (mRecords) { mCarrierNetworkChangeState = active; for (int subId : subIds) { - int phoneId = SubscriptionManager.getPhoneId(subId); + int phoneId = getPhoneIdFromSubId(subId); if (VDBG) { log("notifyCarrierNetworkChange: active=" + active + "subId: " + subId); @@ -1334,7 +1338,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("notifyCellInfoForSubscriber: subId=" + subId + " cellInfo=" + cellInfo); } - int phoneId = SubscriptionManager.getPhoneId(subId); + int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { if (validatePhoneId(phoneId)) { mCellInfo.set(phoneId, cellInfo); @@ -1425,7 +1429,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("notifyCallForwardingChangedForSubscriber: subId=" + subId + " cfi=" + cfi); } - int phoneId = SubscriptionManager.getPhoneId(subId); + int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { if (validatePhoneId(phoneId)) { mCallForwarding[phoneId] = cfi; @@ -1453,7 +1457,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (!checkNotifyPermission("notifyDataActivity()" )) { return; } - int phoneId = SubscriptionManager.getPhoneId(subId); + int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { if (validatePhoneId(phoneId)) { mDataActivity[phoneId] = state; @@ -1610,7 +1614,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { handleRemoveListLocked(); } - broadcastDataConnectionFailed(apnType, subId); } public void notifyCellLocation(Bundle cellLocation) { @@ -1627,7 +1630,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { log("notifyCellLocationForSubscriber: subId=" + subId + " cellLocation=" + cellLocation); } - int phoneId = SubscriptionManager.getPhoneId(subId); + int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { if (validatePhoneId(phoneId)) { mCellLocation[phoneId] = cellLocation; @@ -1736,7 +1739,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (!checkNotifyPermission("notifyImsCallDisconnectCause()")) { return; } - int phoneId = SubscriptionManager.getPhoneId(subId); + int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { if (validatePhoneId(phoneId)) { mImsReasonInfo.set(phoneId, imsReasonInfo); @@ -1803,7 +1806,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (VDBG) { log("notifySrvccStateChanged: subId=" + subId + " srvccState=" + state); } - int phoneId = SubscriptionManager.getPhoneId(subId); + int phoneId = getPhoneIdFromSubId(subId); synchronized (mRecords) { if (validatePhoneId(phoneId)) { mSrvccState[phoneId] = state; @@ -2209,7 +2212,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); } // If the phoneId is invalid, the broadcast is for overall call state. - if (phoneId != SubscriptionManager.INVALID_PHONE_INDEX) { + if (phoneId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) { intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId); intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, phoneId); } @@ -2259,13 +2262,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; @@ -2653,8 +2649,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return "TD_SCDMA"; case TelephonyManager.NETWORK_TYPE_IWLAN: return "IWLAN"; - case TelephonyManager.NETWORK_TYPE_LTE_CA: - return "LTE_CA"; + + //TODO: This network type is marked as hidden because it is not a + // true network type and we are looking to remove it completely from the available list + // of network types. Since this method is only used for logging, in the event that this + // network type is selected, the log will read as "Unknown." + //case TelephonyManager.NETWORK_TYPE_LTE_CA: + // return "LTE_CA"; + case TelephonyManager.NETWORK_TYPE_NR: return "NR"; default: @@ -2675,4 +2677,18 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private static CallQuality createCallQuality() { return new CallQuality(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } + + private int getPhoneIdFromSubId(int subId) { + SubscriptionManager subManager = (SubscriptionManager) + mContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); + if (subManager == null) return INVALID_SIM_SLOT_INDEX; + + if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { + subId = SubscriptionManager.getDefaultSubscriptionId(); + } + + SubscriptionInfo info = subManager.getActiveSubscriptionInfo(subId); + if (info == null) return INVALID_SIM_SLOT_INDEX; + return info.getSimSlotIndex(); + } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 1c4f1e3ed5bf..2af04ae3f800 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5280,7 +5280,7 @@ public class ActivityManagerService extends IActivityManager.Stub storageManager.commitChanges(); } catch (Exception e) { PowerManager pm = (PowerManager) - mInjector.getContext().getSystemService(Context.POWER_SERVICE); + mContext.getSystemService(Context.POWER_SERVICE); pm.reboot("Checkpoint commit failed"); } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index b406ce6c3ca8..972b10608056 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -2899,33 +2899,37 @@ final class ActivityManagerShellCommand extends ShellCommand { } ArraySet<Long> enabled = new ArraySet<>(); ArraySet<Long> disabled = new ArraySet<>(); - switch (toggleValue) { - case "enable": - enabled.add(changeId); - pw.println("Enabled change " + changeId + " for " + packageName + "."); - CompatibilityChangeConfig overrides = - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(enabled, disabled)); - platformCompat.setOverrides(overrides, packageName); - return 0; - case "disable": - disabled.add(changeId); - pw.println("Disabled change " + changeId + " for " + packageName + "."); - overrides = - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(enabled, disabled)); - platformCompat.setOverrides(overrides, packageName); - return 0; - case "reset": - if (platformCompat.clearOverride(changeId, packageName)) { - pw.println("Reset change " + changeId + " for " + packageName - + " to default value."); - } else { - pw.println("No override exists for changeId " + changeId + "."); - } - return 0; - default: - pw.println("Invalid toggle value: '" + toggleValue + "'."); + try { + switch (toggleValue) { + case "enable": + enabled.add(changeId); + CompatibilityChangeConfig overrides = + new CompatibilityChangeConfig( + new Compatibility.ChangeConfig(enabled, disabled)); + platformCompat.setOverrides(overrides, packageName); + pw.println("Enabled change " + changeId + " for " + packageName + "."); + return 0; + case "disable": + disabled.add(changeId); + overrides = + new CompatibilityChangeConfig( + new Compatibility.ChangeConfig(enabled, disabled)); + platformCompat.setOverrides(overrides, packageName); + pw.println("Disabled change " + changeId + " for " + packageName + "."); + return 0; + case "reset": + if (platformCompat.clearOverride(changeId, packageName)) { + pw.println("Reset change " + changeId + " for " + packageName + + " to default value."); + } else { + pw.println("No override exists for changeId " + changeId + "."); + } + return 0; + default: + pw.println("Invalid toggle value: '" + toggleValue + "'."); + } + } catch (SecurityException e) { + pw.println(e.getMessage()); } return -1; } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index f5579761c151..766fa3ba55c1 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -1363,7 +1363,7 @@ public final class ProcessList { final int procCount = procs.size(); for (int i = 0; i < procCount; i++) { final int procUid = procs.keyAt(i); - if (UserHandle.isApp(procUid) || !UserHandle.isSameUser(procUid, uid)) { + if (!UserHandle.isCore(procUid) || !UserHandle.isSameUser(procUid, uid)) { // Don't use an app process or different user process for system component. continue; } diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java index cf83dd630a29..f15d999e1006 100644 --- a/services/core/java/com/android/server/compat/CompatConfig.java +++ b/services/core/java/com/android/server/compat/CompatConfig.java @@ -17,8 +17,10 @@ package com.android.server.compat; import android.compat.Compatibility.ChangeConfig; +import android.content.Context; import android.content.pm.ApplicationInfo; import android.os.Environment; +import android.os.RemoteException; import android.text.TextUtils; import android.util.LongArray; import android.util.LongSparseArray; @@ -26,8 +28,11 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.compat.AndroidBuildClassifier; import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.compat.CompatibilityChangeInfo; +import com.android.internal.compat.IOverrideValidator; +import com.android.internal.compat.OverrideAllowedState; import com.android.server.compat.config.Change; import com.android.server.compat.config.XmlParser; @@ -54,22 +59,14 @@ final class CompatConfig { private static final String TAG = "CompatConfig"; - private static final CompatConfig sInstance = new CompatConfig().initConfigFromLib( - Environment.buildPath( - Environment.getRootDirectory(), "etc", "compatconfig")); - @GuardedBy("mChanges") private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>(); - @VisibleForTesting - CompatConfig() { - } + private IOverrideValidator mOverrideValidator; - /** - * @return The static instance of this class to be used within the system server. - */ - static CompatConfig get() { - return sInstance; + @VisibleForTesting + CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) { + mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this); } /** @@ -159,8 +156,12 @@ final class CompatConfig { * @param enabled If the change should be enabled or disabled. * @return {@code true} if the change existed before adding the override. */ - boolean addOverride(long changeId, String packageName, boolean enabled) { + boolean addOverride(long changeId, String packageName, boolean enabled) + throws RemoteException, SecurityException { boolean alreadyKnown = true; + OverrideAllowedState allowedState = + mOverrideValidator.getOverrideAllowedState(changeId, packageName); + allowedState.enforce(changeId, packageName); synchronized (mChanges) { CompatChange c = mChanges.get(changeId); if (c == null) { @@ -186,6 +187,20 @@ final class CompatConfig { } /** + * Returns the minimum sdk version for which this change should be enabled (or 0 if it is not + * target sdk gated). + */ + int minTargetSdkForChangeId(long changeId) { + synchronized (mChanges) { + CompatChange c = mChanges.get(changeId); + if (c == null) { + return 0; + } + return c.getEnableAfterTargetSdk(); + } + } + + /** * Removes an override previously added via {@link #addOverride(long, String, boolean)}. This * restores the default behaviour for the given change and app, once any app processes have been * restarted. @@ -194,34 +209,44 @@ final class CompatConfig { * @param packageName The app package name that was overridden. * @return {@code true} if an override existed; */ - boolean removeOverride(long changeId, String packageName) { + boolean removeOverride(long changeId, String packageName) + throws RemoteException, SecurityException { boolean overrideExists = false; synchronized (mChanges) { CompatChange c = mChanges.get(changeId); - if (c != null) { - overrideExists = true; - c.removePackageOverride(packageName); + try { + if (c != null) { + OverrideAllowedState allowedState = + mOverrideValidator.getOverrideAllowedState(changeId, packageName); + allowedState.enforce(changeId, packageName); + overrideExists = true; + c.removePackageOverride(packageName); + } + } catch (RemoteException e) { + // Should never occur, since validator is in the same process. + throw new RuntimeException("Unable to call override validator!", e); } } return overrideExists; } /** - * Overrides the enabled state for a given change and app. This method is intended to be used - * *only* for debugging purposes. + * Overrides the enabled state for a given change and app. * * <p>Note, package overrides are not persistent and will be lost on system or runtime restart. * * @param overrides list of overrides to default changes config. * @param packageName app for which the overrides will be applied. */ - void addOverrides(CompatibilityChangeConfig overrides, String packageName) { + void addOverrides(CompatibilityChangeConfig overrides, String packageName) + throws RemoteException, SecurityException { synchronized (mChanges) { for (Long changeId : overrides.enabledChanges()) { addOverride(changeId, packageName, true); } for (Long changeId : overrides.disabledChanges()) { addOverride(changeId, packageName, false); + } } } @@ -235,10 +260,22 @@ final class CompatConfig { * * @param packageName The package for which the overrides should be purged. */ - void removePackageOverrides(String packageName) { + void removePackageOverrides(String packageName) throws RemoteException, SecurityException { synchronized (mChanges) { for (int i = 0; i < mChanges.size(); ++i) { - mChanges.valueAt(i).removePackageOverride(packageName); + try { + CompatChange change = mChanges.valueAt(i); + OverrideAllowedState allowedState = + mOverrideValidator.getOverrideAllowedState(change.getId(), + packageName); + allowedState.enforce(change.getId(), packageName); + if (change != null) { + mChanges.valueAt(i).removePackageOverride(packageName); + } + } catch (RemoteException e) { + // Should never occur, since validator is in the same process. + throw new RuntimeException("Unable to call override validator!", e); + } } } } @@ -326,17 +363,23 @@ final class CompatConfig { } } - CompatConfig initConfigFromLib(File libraryDir) { + static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) { + CompatConfig config = new CompatConfig(androidBuildClassifier, context); + config.initConfigFromLib(Environment.buildPath( + Environment.getRootDirectory(), "etc", "compatconfig")); + return config; + } + + void initConfigFromLib(File libraryDir) { if (!libraryDir.exists() || !libraryDir.isDirectory()) { Slog.e(TAG, "No directory " + libraryDir + ", skipping"); - return this; + return; } for (File f : libraryDir.listFiles()) { Slog.d(TAG, "Found a config file: " + f.getPath()); //TODO(b/138222363): Handle duplicate ids across config files. readConfig(f); } - return this; } private void readConfig(File configFile) { @@ -350,4 +393,7 @@ final class CompatConfig { } } + IOverrideValidator getOverrideValidator() { + return mOverrideValidator; + } } diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java new file mode 100644 index 000000000000..dfc00806992b --- /dev/null +++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.compat; + +import static com.android.internal.compat.OverrideAllowedState.ALLOWED; +import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK; +import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE; +import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH; +import static com.android.internal.compat.OverrideAllowedState.PACKAGE_DOES_NOT_EXIST; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.compat.AndroidBuildClassifier; +import com.android.internal.compat.IOverrideValidator; +import com.android.internal.compat.OverrideAllowedState; + +/** + * Implementation of the policy for allowing compat change overrides. + */ +public class OverrideValidatorImpl extends IOverrideValidator.Stub { + + private AndroidBuildClassifier mAndroidBuildClassifier; + private Context mContext; + private CompatConfig mCompatConfig; + + @VisibleForTesting + OverrideValidatorImpl(AndroidBuildClassifier androidBuildClassifier, + Context context, CompatConfig config) { + mAndroidBuildClassifier = androidBuildClassifier; + mContext = context; + mCompatConfig = config; + } + + @Override + public OverrideAllowedState getOverrideAllowedState(long changeId, String packageName) { + boolean debuggableBuild = false; + boolean finalBuild = false; + + debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild(); + finalBuild = mAndroidBuildClassifier.isFinalBuild(); + + // Allow any override for userdebug or eng builds. + if (debuggableBuild) { + return new OverrideAllowedState(ALLOWED, -1, -1); + } + PackageManager packageManager = mContext.getPackageManager(); + if (packageManager == null) { + throw new IllegalStateException("No PackageManager!"); + } + ApplicationInfo applicationInfo; + try { + applicationInfo = packageManager.getApplicationInfo(packageName, 0); + } catch (NameNotFoundException e) { + return new OverrideAllowedState(PACKAGE_DOES_NOT_EXIST, -1, -1); + } + int appTargetSdk = applicationInfo.targetSdkVersion; + // Only allow overriding debuggable apps. + if ((applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) { + return new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1); + } + int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId); + // Do not allow overriding non-target sdk gated changes on user builds + if (minTargetSdk == -1) { + return new OverrideAllowedState(DISABLED_NON_TARGET_SDK, appTargetSdk, minTargetSdk); + } + // Allow overriding any change for debuggable apps on non-final builds. + if (!finalBuild) { + return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk); + } + // Only allow to opt-in for a targetSdk gated change. + if (applicationInfo.targetSdkVersion < minTargetSdk) { + return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk); + } + return new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, appTargetSdk, minTargetSdk); + } +} diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index 4a3d7d69d874..029b7bc32ef3 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -27,9 +27,12 @@ import android.os.UserHandle; import android.util.Slog; import android.util.StatsLog; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.compat.AndroidBuildClassifier; import com.android.internal.compat.ChangeReporter; import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.compat.CompatibilityChangeInfo; +import com.android.internal.compat.IOverrideValidator; import com.android.internal.compat.IPlatformCompat; import com.android.internal.util.DumpUtils; @@ -45,11 +48,21 @@ public class PlatformCompat extends IPlatformCompat.Stub { private final Context mContext; private final ChangeReporter mChangeReporter; + private final CompatConfig mCompatConfig; public PlatformCompat(Context context) { mContext = context; mChangeReporter = new ChangeReporter( StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER); + mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext); + } + + @VisibleForTesting + PlatformCompat(Context context, CompatConfig compatConfig) { + mContext = context; + mChangeReporter = new ChangeReporter( + StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER); + mCompatConfig = compatConfig; } @Override @@ -74,7 +87,7 @@ public class PlatformCompat extends IPlatformCompat.Stub { @Override public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) { - if (CompatConfig.get().isChangeEnabled(changeId, appInfo)) { + if (mCompatConfig.isChangeEnabled(changeId, appInfo)) { reportChange(changeId, appInfo.uid, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED); return true; @@ -121,57 +134,59 @@ public class PlatformCompat extends IPlatformCompat.Stub { * otherwise. */ public boolean registerListener(long changeId, CompatChange.ChangeListener listener) { - return CompatConfig.get().registerListener(changeId, listener); + return mCompatConfig.registerListener(changeId, listener); } @Override - public void setOverrides(CompatibilityChangeConfig overrides, String packageName) { - CompatConfig.get().addOverrides(overrides, packageName); + public void setOverrides(CompatibilityChangeConfig overrides, String packageName) + throws RemoteException, SecurityException { + mCompatConfig.addOverrides(overrides, packageName); killPackage(packageName); } @Override - public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) { - CompatConfig.get().addOverrides(overrides, packageName); + public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) + throws RemoteException, SecurityException { + mCompatConfig.addOverrides(overrides, packageName); } @Override - public void clearOverrides(String packageName) { - CompatConfig config = CompatConfig.get(); - config.removePackageOverrides(packageName); + public void clearOverrides(String packageName) throws RemoteException, SecurityException { + mCompatConfig.removePackageOverrides(packageName); killPackage(packageName); } @Override - public void clearOverridesForTest(String packageName) { - CompatConfig config = CompatConfig.get(); - config.removePackageOverrides(packageName); + public void clearOverridesForTest(String packageName) + throws RemoteException, SecurityException { + mCompatConfig.removePackageOverrides(packageName); } @Override - public boolean clearOverride(long changeId, String packageName) { - boolean existed = CompatConfig.get().removeOverride(changeId, packageName); + public boolean clearOverride(long changeId, String packageName) + throws RemoteException, SecurityException { + boolean existed = mCompatConfig.removeOverride(changeId, packageName); killPackage(packageName); return existed; } @Override public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) { - return CompatConfig.get().getAppConfig(appInfo); + return mCompatConfig.getAppConfig(appInfo); } @Override public CompatibilityChangeInfo[] listAllChanges() { - return CompatConfig.get().dumpChanges(); + return mCompatConfig.dumpChanges(); } /** * Check whether the change is known to the compat config. - * @param changeId + * * @return {@code true} if the change is known. */ public boolean isKnownChangeId(long changeId) { - return CompatConfig.get().isKnownChangeId(changeId); + return mCompatConfig.isKnownChangeId(changeId); } @@ -181,11 +196,11 @@ public class PlatformCompat extends IPlatformCompat.Stub { * * @param appInfo The app in question * @return A sorted long array of change IDs. We use a primitive array to minimize memory - * footprint: Every app process will store this array statically so we aim to reduce - * overhead as much as possible. + * footprint: Every app process will store this array statically so we aim to reduce + * overhead as much as possible. */ public long[] getDisabledChanges(ApplicationInfo appInfo) { - return CompatConfig.get().getDisabledChanges(appInfo); + return mCompatConfig.getDisabledChanges(appInfo); } /** @@ -195,18 +210,24 @@ public class PlatformCompat extends IPlatformCompat.Stub { * @return The change ID, or {@code -1} if no change with that name exists. */ public long lookupChangeId(String name) { - return CompatConfig.get().lookupChangeId(name); + return mCompatConfig.lookupChangeId(name); } @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return; - CompatConfig.get().dumpConfig(pw); + mCompatConfig.dumpConfig(pw); + } + + @Override + public IOverrideValidator getOverrideValidator() { + return mCompatConfig.getOverrideValidator(); } /** * Clears information stored about events reported on behalf of an app. * To be called once upon app start or end. A second call would be a no-op. + * * @param appInfo the app to reset */ public void resetReporting(ApplicationInfo appInfo) { diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java index 668630e06cf0..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); @@ -129,4 +138,10 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub { 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 e30ac8aa0b0c..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, @@ -184,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(); } @@ -253,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") @@ -348,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) { @@ -415,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") @@ -507,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 @@ -514,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/wallpaper/GLHelper.java b/services/core/java/com/android/server/wallpaper/GLHelper.java new file mode 100644 index 000000000000..1d733f53f055 --- /dev/null +++ b/services/core/java/com/android/server/wallpaper/GLHelper.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wallpaper; + +import static android.opengl.EGL14.EGL_ALPHA_SIZE; +import static android.opengl.EGL14.EGL_BLUE_SIZE; +import static android.opengl.EGL14.EGL_CONFIG_CAVEAT; +import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION; +import static android.opengl.EGL14.EGL_DEFAULT_DISPLAY; +import static android.opengl.EGL14.EGL_DEPTH_SIZE; +import static android.opengl.EGL14.EGL_GREEN_SIZE; +import static android.opengl.EGL14.EGL_HEIGHT; +import static android.opengl.EGL14.EGL_NONE; +import static android.opengl.EGL14.EGL_NO_CONTEXT; +import static android.opengl.EGL14.EGL_NO_DISPLAY; +import static android.opengl.EGL14.EGL_NO_SURFACE; +import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT; +import static android.opengl.EGL14.EGL_RED_SIZE; +import static android.opengl.EGL14.EGL_RENDERABLE_TYPE; +import static android.opengl.EGL14.EGL_STENCIL_SIZE; +import static android.opengl.EGL14.EGL_WIDTH; +import static android.opengl.EGL14.eglChooseConfig; +import static android.opengl.EGL14.eglCreateContext; +import static android.opengl.EGL14.eglCreatePbufferSurface; +import static android.opengl.EGL14.eglDestroyContext; +import static android.opengl.EGL14.eglDestroySurface; +import static android.opengl.EGL14.eglGetDisplay; +import static android.opengl.EGL14.eglGetError; +import static android.opengl.EGL14.eglInitialize; +import static android.opengl.EGL14.eglMakeCurrent; +import static android.opengl.EGL14.eglTerminate; +import static android.opengl.GLES20.GL_MAX_TEXTURE_SIZE; +import static android.opengl.GLES20.glGetIntegerv; + +import android.opengl.EGLConfig; +import android.opengl.EGLContext; +import android.opengl.EGLDisplay; +import android.opengl.EGLSurface; +import android.opengl.GLUtils; +import android.os.SystemProperties; +import android.util.Log; + +class GLHelper { + private static final String TAG = GLHelper.class.getSimpleName(); + private static final int sMaxTextureSize; + + static { + int maxTextureSize = SystemProperties.getInt("sys.max_texture_size", 0); + sMaxTextureSize = maxTextureSize > 0 ? maxTextureSize : retrieveTextureSizeFromGL(); + } + + private static int retrieveTextureSizeFromGL() { + try { + String err; + + // Before we can retrieve info from GL, + // we have to create EGLContext, EGLConfig and EGLDisplay first. + // We will fail at querying info from GL once one of above failed. + // When this happens, we will use defValue instead. + EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (eglDisplay == null || eglDisplay == EGL_NO_DISPLAY) { + err = "eglGetDisplay failed: " + GLUtils.getEGLErrorString(eglGetError()); + throw new RuntimeException(err); + } + + if (!eglInitialize(eglDisplay, null, 0 /* majorOffset */, null, 1 /* minorOffset */)) { + err = "eglInitialize failed: " + GLUtils.getEGLErrorString(eglGetError()); + throw new RuntimeException(err); + } + + EGLConfig eglConfig = null; + int[] configsCount = new int[1]; + EGLConfig[] configs = new EGLConfig[1]; + int[] configSpec = new int[] { + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 0, + EGL_DEPTH_SIZE, 0, + EGL_STENCIL_SIZE, 0, + EGL_CONFIG_CAVEAT, EGL_NONE, + EGL_NONE + }; + + if (!eglChooseConfig(eglDisplay, configSpec, 0 /* attrib_listOffset */, + configs, 0 /* configOffset */, 1 /* config_size */, + configsCount, 0 /* num_configOffset */)) { + err = "eglChooseConfig failed: " + GLUtils.getEGLErrorString(eglGetError()); + throw new RuntimeException(err); + } else if (configsCount[0] > 0) { + eglConfig = configs[0]; + } + + if (eglConfig == null) { + throw new RuntimeException("eglConfig not initialized!"); + } + + int[] attr_list = new int[] {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; + EGLContext eglContext = eglCreateContext( + eglDisplay, eglConfig, EGL_NO_CONTEXT, attr_list, 0 /* offset */); + + if (eglContext == null || eglContext == EGL_NO_CONTEXT) { + err = "eglCreateContext failed: " + GLUtils.getEGLErrorString(eglGetError()); + throw new RuntimeException(err); + } + + // We create a push buffer temporarily for querying info from GL. + int[] attrs = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}; + EGLSurface eglSurface = + eglCreatePbufferSurface(eglDisplay, eglConfig, attrs, 0 /* offset */); + eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext); + + // Now, we are ready to query the info from GL. + int[] maxSize = new int[1]; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, maxSize, 0 /* offset */); + + // We have got the info we want, release all egl resources. + eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(eglDisplay, eglSurface); + eglDestroyContext(eglDisplay, eglContext); + eglTerminate(eglDisplay); + return maxSize[0]; + } catch (RuntimeException e) { + Log.w(TAG, "Retrieve from GL failed", e); + return Integer.MAX_VALUE; + } + } + + static int getMaxTextureSize() { + return sMaxTextureSize; + } +} + diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index b0f1e5d69be4..991c09a97bf5 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -134,6 +134,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub private static final boolean DEBUG = false; private static final boolean DEBUG_LIVE = true; + // This 100MB limitation is defined in RecordingCanvas. + private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; + public static class Lifecycle extends SystemService { private IWallpaperManagerService mService; @@ -572,7 +575,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // Only generate crop for default display. final DisplayData wpData = getDisplayDataOrCreate(DEFAULT_DISPLAY); - Rect cropHint = new Rect(wallpaper.cropHint); + final Rect cropHint = new Rect(wallpaper.cropHint); + final DisplayInfo displayInfo = new DisplayInfo(); + mDisplayManager.getDisplay(DEFAULT_DISPLAY).getDisplayInfo(displayInfo); if (DEBUG) { Slog.v(TAG, "Generating crop for new wallpaper(s): 0x" @@ -618,12 +623,12 @@ public class WallpaperManagerService extends IWallpaperManager.Stub } // scale if the crop height winds up not matching the recommended metrics - needScale = (wpData.mHeight != cropHint.height()); + needScale = wpData.mHeight != cropHint.height() + || cropHint.height() > GLHelper.getMaxTextureSize() + || cropHint.width() > GLHelper.getMaxTextureSize(); //make sure screen aspect ratio is preserved if width is scaled under screen size if (needScale) { - final DisplayInfo displayInfo = new DisplayInfo(); - mDisplayManager.getDisplay(DEFAULT_DISPLAY).getDisplayInfo(displayInfo); final float scaleByHeight = (float) wpData.mHeight / (float) cropHint.height(); final int newWidth = (int) (cropHint.width() * scaleByHeight); if (newWidth < displayInfo.logicalWidth) { @@ -644,14 +649,29 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (!needCrop && !needScale) { // Simple case: the nominal crop fits what we want, so we take // the whole thing and just copy the image file directly. - if (DEBUG) { - Slog.v(TAG, "Null crop of new wallpaper; copying"); + + // TODO: It is not accurate to estimate bitmap size without decoding it, + // may be we can try to remove this optimized way in the future, + // that means, we will always go into the 'else' block. + + // This is just a quick estimation, may be smaller than it is. + long estimateSize = options.outWidth * options.outHeight * 4; + + // A bitmap over than MAX_BITMAP_SIZE will make drawBitmap() fail. + // Please see: RecordingCanvas#throwIfCannotDraw. + if (estimateSize < MAX_BITMAP_SIZE) { + success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile); } - success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile); + if (!success) { wallpaper.cropFile.delete(); // TODO: fall back to default wallpaper in this case } + + if (DEBUG) { + Slog.v(TAG, "Null crop of new wallpaper, estimate size=" + + estimateSize + ", success=" + success); + } } else { // Fancy case: crop and scale. First, we decode and scale down if appropriate. FileOutputStream f = null; @@ -665,49 +685,78 @@ public class WallpaperManagerService extends IWallpaperManager.Stub // We calculate the largest power-of-two under the actual ratio rather than // just let the decode take care of it because we also want to remap where the // cropHint rectangle lies in the decoded [super]rect. - final BitmapFactory.Options scaler; final int actualScale = cropHint.height() / wpData.mHeight; int scale = 1; - while (2*scale < actualScale) { + while (2 * scale <= actualScale) { scale *= 2; } - if (scale > 1) { - scaler = new BitmapFactory.Options(); - scaler.inSampleSize = scale; + options.inSampleSize = scale; + options.inJustDecodeBounds = false; + + final Rect estimateCrop = new Rect(cropHint); + estimateCrop.scale(1f / options.inSampleSize); + final float hRatio = (float) wpData.mHeight / estimateCrop.height(); + final int destHeight = (int) (estimateCrop.height() * hRatio); + final int destWidth = (int) (estimateCrop.width() * hRatio); + + // We estimated an invalid crop, try to adjust the cropHint to get a valid one. + if (destWidth > GLHelper.getMaxTextureSize()) { + int newHeight = (int) (wpData.mHeight / hRatio); + int newWidth = (int) (wpData.mWidth / hRatio); + if (DEBUG) { - Slog.v(TAG, "Downsampling cropped rect with scale " + scale); + Slog.v(TAG, "Invalid crop dimensions, trying to adjust."); } - } else { - scaler = null; + + estimateCrop.set(cropHint); + estimateCrop.left += (cropHint.width() - newWidth) / 2; + estimateCrop.top += (cropHint.height() - newHeight) / 2; + estimateCrop.right = estimateCrop.left + newWidth; + estimateCrop.bottom = estimateCrop.top + newHeight; + cropHint.set(estimateCrop); + estimateCrop.scale(1f / options.inSampleSize); + } + + // We've got the safe cropHint; now we want to scale it properly to + // the desired rectangle. + // That's a height-biased operation: make it fit the hinted height. + final int safeHeight = (int) (estimateCrop.height() * hRatio); + final int safeWidth = (int) (estimateCrop.width() * hRatio); + + if (DEBUG) { + Slog.v(TAG, "Decode parameters:"); + Slog.v(TAG, " cropHint=" + cropHint + ", estimateCrop=" + estimateCrop); + Slog.v(TAG, " down sampling=" + options.inSampleSize + + ", hRatio=" + hRatio); + Slog.v(TAG, " dest=" + destWidth + "x" + destHeight); + Slog.v(TAG, " safe=" + safeWidth + "x" + safeHeight); + Slog.v(TAG, " maxTextureSize=" + GLHelper.getMaxTextureSize()); } - Bitmap cropped = decoder.decodeRegion(cropHint, scaler); + + Bitmap cropped = decoder.decodeRegion(cropHint, options); decoder.recycle(); if (cropped == null) { Slog.e(TAG, "Could not decode new wallpaper"); } else { - // We've got the extracted crop; now we want to scale it properly to - // the desired rectangle. That's a height-biased operation: make it - // fit the hinted height, and accept whatever width we end up with. - cropHint.offsetTo(0, 0); - cropHint.right /= scale; // adjust by downsampling factor - cropHint.bottom /= scale; - final float heightR = - ((float) wpData.mHeight) / ((float) cropHint.height()); - if (DEBUG) { - Slog.v(TAG, "scale " + heightR + ", extracting " + cropHint); - } - final int destWidth = (int)(cropHint.width() * heightR); + // We are safe to create final crop with safe dimensions now. final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped, - destWidth, wpData.mHeight, true); + safeWidth, safeHeight, true); if (DEBUG) { Slog.v(TAG, "Final extract:"); Slog.v(TAG, " dims: w=" + wpData.mWidth + " h=" + wpData.mHeight); - Slog.v(TAG, " out: w=" + finalCrop.getWidth() + Slog.v(TAG, " out: w=" + finalCrop.getWidth() + " h=" + finalCrop.getHeight()); } + // A bitmap over than MAX_BITMAP_SIZE will make drawBitmap() fail. + // Please see: RecordingCanvas#throwIfCannotDraw. + if (finalCrop.getByteCount() > MAX_BITMAP_SIZE) { + throw new RuntimeException( + "Too large bitmap, limit=" + MAX_BITMAP_SIZE); + } + f = new FileOutputStream(wallpaper.cropFile); bos = new BufferedOutputStream(f, 32*1024); finalCrop.compress(Bitmap.CompressFormat.JPEG, 100, bos); @@ -1981,6 +2030,11 @@ public class WallpaperManagerService extends IWallpaperManager.Stub if (!isWallpaperSupported(callingPackage)) { return; } + + // Make sure both width and height are not larger than max texture size. + width = Math.min(width, GLHelper.getMaxTextureSize()); + height = Math.min(height, GLHelper.getMaxTextureSize()); + synchronized (mLock) { int userId = UserHandle.getCallingUserId(); WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM); diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 2b1c07ba40b1..3b66c72c1025 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -124,6 +124,7 @@ cc_defaults { "android.hardware.thermal@1.0", "android.hardware.tv.cec@1.0", "android.hardware.tv.input@1.0", + "android.hardware.vibrator-cpp", "android.hardware.vibrator@1.0", "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.2", @@ -133,7 +134,6 @@ cc_defaults { "android.frameworks.sensorservice@1.0", "android.system.suspend@1.0", "suspend_control_aidl_interface-cpp", - "vintf-vibrator-cpp", ], static_libs: [ diff --git a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java index f3c76b609c25..8871348d0027 100644 --- a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java +++ b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java @@ -28,6 +28,7 @@ import static org.mockito.Mockito.when; import android.app.admin.DevicePolicyManagerInternal; import android.appwidget.AppWidgetManager; +import android.appwidget.AppWidgetManagerInternal; import android.appwidget.AppWidgetProviderInfo; import android.appwidget.PendingHostUpdate; import android.content.BroadcastReceiver; @@ -80,6 +81,7 @@ public class AppWidgetServiceImplTest extends InstrumentationTestCase { super.setUp(); LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); LocalServices.removeServiceForTest(ShortcutServiceInternal.class); + LocalServices.removeServiceForTest(AppWidgetManagerInternal.class); mTestContext = new TestContext(); mPkgName = mTestContext.getOpPackageName(); diff --git a/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java b/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java new file mode 100644 index 000000000000..d0767ccb6f87 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.compat; + +import android.content.pm.ApplicationInfo; + +class ApplicationInfoBuilder { + private boolean mIsDebuggable; + private int mTargetSdk; + private String mPackageName; + + private ApplicationInfoBuilder() { + mTargetSdk = -1; + } + + static ApplicationInfoBuilder create() { + return new ApplicationInfoBuilder(); + } + + ApplicationInfoBuilder withTargetSdk(int targetSdk) { + mTargetSdk = targetSdk; + return this; + } + + ApplicationInfoBuilder debuggable() { + mIsDebuggable = true; + return this; + } + + ApplicationInfoBuilder withPackageName(String packageName) { + mPackageName = packageName; + return this; + } + + ApplicationInfo build() { + final ApplicationInfo applicationInfo = new ApplicationInfo(); + if (mIsDebuggable) { + applicationInfo.flags |= ApplicationInfo.FLAG_DEBUGGABLE; + } + applicationInfo.packageName = mPackageName; + applicationInfo.targetSdkVersion = mTargetSdk; + return applicationInfo; + } +} diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java new file mode 100644 index 000000000000..328c71dbc7db --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.compat; + +import android.content.Context; + +import com.android.internal.compat.AndroidBuildClassifier; + +import java.util.ArrayList; + +/** + * Helper class for creating a CompatConfig. + */ +class CompatConfigBuilder { + private ArrayList<CompatChange> mChanges; + private AndroidBuildClassifier mBuildClassifier; + private Context mContext; + + private CompatConfigBuilder(AndroidBuildClassifier buildClassifier, Context context) { + mChanges = new ArrayList<>(); + mBuildClassifier = buildClassifier; + mContext = context; + } + + static CompatConfigBuilder create(AndroidBuildClassifier buildClassifier, Context context) { + return new CompatConfigBuilder(buildClassifier, context); + } + + CompatConfigBuilder addTargetSdkChangeWithId(int sdk, long id) { + mChanges.add(new CompatChange(id, "", sdk, false, "")); + return this; + } + + CompatConfigBuilder addTargetSdkDisabledChangeWithId(int sdk, long id) { + mChanges.add(new CompatChange(id, "", sdk, true, "")); + return this; + } + + CompatConfigBuilder addTargetSdkChangeWithIdAndName(int sdk, long id, String name) { + mChanges.add(new CompatChange(id, name, sdk, false, "")); + return this; + } + + CompatConfigBuilder addTargetSdkChangeWithIdAndDescription(int sdk, long id, + String description) { + mChanges.add(new CompatChange(id, "", sdk, false, description)); + return this; + } + + CompatConfigBuilder addEnabledChangeWithId(long id) { + mChanges.add(new CompatChange(id, "", -1, false, "")); + return this; + } + + CompatConfigBuilder addEnabledChangeWithIdAndName(long id, String name) { + mChanges.add(new CompatChange(id, name, -1, false, "")); + return this; + } + CompatConfigBuilder addEnabledChangeWithIdAndDescription(long id, String description) { + mChanges.add(new CompatChange(id, "", -1, false, description)); + return this; + } + + CompatConfigBuilder addDisabledChangeWithId(long id) { + mChanges.add(new CompatChange(id, "", -1, true, "")); + return this; + } + + CompatConfigBuilder addDisabledChangeWithIdAndName(long id, String name) { + mChanges.add(new CompatChange(id, name, -1, true, "")); + return this; + } + + CompatConfigBuilder addDisabledChangeWithIdAndDescription(long id, String description) { + mChanges.add(new CompatChange(id, "", -1, true, description)); + return this; + } + + CompatConfig build() { + CompatConfig config = new CompatConfig(mBuildClassifier, mContext); + for (CompatChange change : mChanges) { + config.addChange(change); + } + return config; + } +} diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java index cb99c118a407..407f67e2fd8e 100644 --- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java @@ -18,12 +18,25 @@ package com.android.server.compat; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertThrows; + +import android.content.Context; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.compat.AndroidBuildClassifier; + +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.io.File; import java.io.FileOutputStream; @@ -34,12 +47,12 @@ import java.util.UUID; @RunWith(AndroidJUnit4.class) public class CompatConfigTest { - private ApplicationInfo makeAppInfo(String pName, int targetSdkVersion) { - ApplicationInfo ai = new ApplicationInfo(); - ai.packageName = pName; - ai.targetSdkVersion = targetSdkVersion; - return ai; - } + @Mock + private Context mContext; + @Mock + PackageManager mPackageManager; + @Mock + private AndroidBuildClassifier mBuildClassifier; private File createTempDir() { String base = System.getProperty("java.io.tmpdir"); @@ -54,112 +67,206 @@ public class CompatConfigTest { os.close(); } + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + // Assume userdebug/eng non-final build + when(mBuildClassifier.isDebuggableBuild()).thenReturn(true); + when(mBuildClassifier.isFinalBuild()).thenReturn(false); + } + + @Test + public void testUnknownChangeEnabled() throws Exception { + CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); + assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create().build())) + .isTrue(); + } + @Test - public void testUnknownChangeEnabled() { - CompatConfig pc = new CompatConfig(); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isTrue(); + public void testDisabledChangeDisabled() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledChangeWithId(1234L) + .build(); + + assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create().build())) + .isFalse(); } @Test - public void testDisabledChangeDisabled() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, "")); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse(); + public void testTargetSdkChangeDisabled() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addTargetSdkChangeWithId(2, 1234L) + .build(); + + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(2).build())) + .isFalse(); } @Test - public void testTargetSdkChangeDisabled() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false, null)); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse(); + public void testTargetSdkChangeEnabled() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addTargetSdkChangeWithId(2, 1234L) + .build(); + + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue(); } @Test - public void testTargetSdkChangeEnabled() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false, "")); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue(); + public void testDisabledOverrideTargetSdkChange() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addTargetSdkDisabledChangeWithId(2, 1234L) + .build(); + + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(3).build())).isFalse(); } @Test - public void testDisabledOverrideTargetSdkChange() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true, null)); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isFalse(); + public void testGetDisabledChanges() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledChangeWithId(1234L) + .addEnabledChangeWithId(2345L) + .build(); + + assertThat(compatConfig.getDisabledChanges( + ApplicationInfoBuilder.create().build())).asList().containsExactly(1234L); } @Test - public void testGetDisabledChanges() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, null)); - pc.addChange(new CompatChange(2345L, "OTHER_CHANGE", -1, false, null)); - assertThat(pc.getDisabledChanges( - makeAppInfo("com.some.package", 2))).asList().containsExactly(1234L); + public void testGetDisabledChangesSorted() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledChangeWithId(1234L) + .addDisabledChangeWithId(123L) + .addDisabledChangeWithId(12L) + .build(); + + assertThat(compatConfig.getDisabledChanges(ApplicationInfoBuilder.create().build())) + .asList().containsExactly(12L, 123L, 1234L); } @Test - public void testGetDisabledChangesSorted() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true, null)); - pc.addChange(new CompatChange(123L, "OTHER_CHANGE", 2, true, null)); - pc.addChange(new CompatChange(12L, "THIRD_CHANGE", 2, true, null)); - assertThat(pc.getDisabledChanges( - makeAppInfo("com.some.package", 2))).asList().containsExactly(12L, 123L, 1234L); + public void testPackageOverrideEnabled() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledChangeWithId(1234L) + .build(); + + compatConfig.addOverride(1234L, "com.some.package", true); + + assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create() + .withPackageName("com.some.package").build())).isTrue(); + assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create() + .withPackageName("com.other.package").build())).isFalse(); } @Test - public void testPackageOverrideEnabled() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true, null)); // disabled - pc.addOverride(1234L, "com.some.package", true); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue(); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isFalse(); + public void testPackageOverrideDisabled() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addEnabledChangeWithId(1234L) + .build(); + + compatConfig.addOverride(1234L, "com.some.package", false); + + assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create() + .withPackageName("com.some.package").build())).isFalse(); + assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create() + .withPackageName("com.other.package").build())).isTrue(); } @Test - public void testPackageOverrideDisabled() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null)); - pc.addOverride(1234L, "com.some.package", false); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse(); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue(); + public void testPackageOverrideUnknownPackage() throws Exception { + CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); + + compatConfig.addOverride(1234L, "com.some.package", false); + + assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create() + .withPackageName("com.some.package").build())).isFalse(); + assertThat(compatConfig.isChangeEnabled(1234L, ApplicationInfoBuilder.create() + .withPackageName("com.other.package").build())).isTrue(); } @Test - public void testPackageOverrideUnknownPackage() { - CompatConfig pc = new CompatConfig(); - pc.addOverride(1234L, "com.some.package", false); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse(); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue(); + public void testPreventAddOverride() throws Exception { + final long changeId = 1234L; + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledChangeWithId(1234L) + .build(); + ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() + .withPackageName("com.some.package") + .build(); + PackageManager packageManager = mock(PackageManager.class); + when(mContext.getPackageManager()).thenReturn(packageManager); + when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt())) + .thenReturn(applicationInfo); + + // Force the validator to prevent overriding the change by using a user build. + when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); + when(mBuildClassifier.isFinalBuild()).thenReturn(true); + + assertThrows(SecurityException.class, + () -> compatConfig.addOverride(1234L, "com.some.package", true) + ); + assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse(); } @Test - public void testPackageOverrideUnknownChange() { - CompatConfig pc = new CompatConfig(); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isTrue(); + public void testPreventRemoveOverride() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addDisabledChangeWithId(1234L) + .build(); + ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() + .withPackageName("com.some.package") + .build(); + when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt())) + .thenReturn(applicationInfo); + // Assume the override was allowed to be added. + compatConfig.addOverride(1234L, "com.some.package", true); + + // Validator allows turning on the change. + assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue(); + + // Reject all override attempts. + // Force the validator to prevent overriding the change by using a user build. + when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); + when(mBuildClassifier.isFinalBuild()).thenReturn(true); + // Try to turn off change, but validator prevents it. + assertThrows(SecurityException.class, + () -> compatConfig.removeOverride(1234L, "com.some.package")); + assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue(); } @Test - public void testRemovePackageOverride() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null)); - pc.addOverride(1234L, "com.some.package", false); - pc.removeOverride(1234L, "com.some.package"); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue(); + public void testRemovePackageOverride() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addEnabledChangeWithId(1234L) + .build(); + ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() + .withPackageName("com.some.package") + .build(); + + assertThat(compatConfig.addOverride(1234L, "com.some.package", false)).isTrue(); + assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse(); + + compatConfig.removeOverride(1234L, "com.some.package"); + assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue(); } @Test - public void testLookupChangeId() { - CompatConfig pc = new CompatConfig(); - pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false, null)); - pc.addChange(new CompatChange(2345L, "ANOTHER_CHANGE", -1, false, null)); - assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(1234L); + public void testLookupChangeId() throws Exception { + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addEnabledChangeWithIdAndName(1234L, "MY_CHANGE") + .addEnabledChangeWithIdAndName(2345L, "MY_OTHER_CHANGE") + .build(); + + assertThat(compatConfig.lookupChangeId("MY_CHANGE")).isEqualTo(1234L); } @Test - public void testLookupChangeIdNotPresent() { - CompatConfig pc = new CompatConfig(); - assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(-1L); + public void testLookupChangeIdNotPresent() throws Exception { + CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); + assertThat(compatConfig.lookupChangeId("MY_CHANGE")).isEqualTo(-1L); } @Test @@ -172,14 +279,17 @@ public class CompatConfigTest { File dir = createTempDir(); writeToFile(dir, "platform_compat_config.xml", configXml); - - CompatConfig pc = new CompatConfig(); - pc.initConfigFromLib(dir); - - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse(); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue(); - assertThat(pc.isChangeEnabled(1235L, makeAppInfo("com.some.package", 5))).isFalse(); - assertThat(pc.isChangeEnabled(1236L, makeAppInfo("com.some.package", 1))).isTrue(); + CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); + compatConfig.initConfigFromLib(dir); + + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse(); + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue(); + assertThat(compatConfig.isChangeEnabled(1235L, + ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse(); + assertThat(compatConfig.isChangeEnabled(1236L, + ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue(); } @Test @@ -195,15 +305,16 @@ public class CompatConfigTest { File dir = createTempDir(); writeToFile(dir, "libcore_platform_compat_config.xml", configXml1); writeToFile(dir, "frameworks_platform_compat_config.xml", configXml2); - - CompatConfig pc = new CompatConfig(); - pc.initConfigFromLib(dir); - - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse(); - assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue(); - assertThat(pc.isChangeEnabled(1235L, makeAppInfo("com.some.package", 5))).isFalse(); - assertThat(pc.isChangeEnabled(1236L, makeAppInfo("com.some.package", 1))).isTrue(); + CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext); + compatConfig.initConfigFromLib(dir); + + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse(); + assertThat(compatConfig.isChangeEnabled(1234L, + ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue(); + assertThat(compatConfig.isChangeEnabled(1235L, + ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse(); + assertThat(compatConfig.isChangeEnabled(1236L, + ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue(); } } - - diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java new file mode 100644 index 000000000000..793296e88169 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/compat/CompatibilityChangeConfigBuilder.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.compat; + +import android.compat.Compatibility; + +import com.android.internal.compat.CompatibilityChangeConfig; + +import java.util.HashSet; +import java.util.Set; + +class CompatibilityChangeConfigBuilder { + private Set<Long> mEnabled; + private Set<Long> mDisabled; + + private CompatibilityChangeConfigBuilder() { + mEnabled = new HashSet<>(); + mDisabled = new HashSet<>(); + } + + static CompatibilityChangeConfigBuilder create() { + return new CompatibilityChangeConfigBuilder(); + } + + CompatibilityChangeConfigBuilder enable(Long id) { + mEnabled.add(id); + return this; + } + + CompatibilityChangeConfigBuilder disable(Long id) { + mDisabled.add(id); + return this; + } + + CompatibilityChangeConfig build() { + return new CompatibilityChangeConfig(new Compatibility.ChangeConfig(mEnabled, mDisabled)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java new file mode 100644 index 000000000000..ecd07bdc4544 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java @@ -0,0 +1,383 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.compat; + +import static com.android.internal.compat.OverrideAllowedState.ALLOWED; +import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK; +import static com.android.internal.compat.OverrideAllowedState.DISABLED_NOT_DEBUGGABLE; +import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_SDK_TOO_HIGH; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.PackageManager; + +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.compat.AndroidBuildClassifier; +import com.android.internal.compat.IOverrideValidator; +import com.android.internal.compat.OverrideAllowedState; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +public class OverrideValidatorImplTest { + private static final String PACKAGE_NAME = "my.package"; + private static final int TARGET_SDK = 10; + private static final int TARGET_SDK_BEFORE = 9; + private static final int TARGET_SDK_AFTER = 11; + + @Mock + private PackageManager mPackageManager; + @Mock + Context mContext; + + private AndroidBuildClassifier debuggableBuild() { + AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class); + when(buildClassifier.isDebuggableBuild()).thenReturn(true); + return buildClassifier; + } + + private AndroidBuildClassifier betaBuild() { + AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class); + when(buildClassifier.isDebuggableBuild()).thenReturn(false); + when(buildClassifier.isFinalBuild()).thenReturn(false); + return buildClassifier; + } + + private AndroidBuildClassifier finalBuild() { + AndroidBuildClassifier buildClassifier = mock(AndroidBuildClassifier.class); + when(buildClassifier.isDebuggableBuild()).thenReturn(false); + when(buildClassifier.isFinalBuild()).thenReturn(true); + return buildClassifier; + } + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + } + + @Test + public void getOverrideAllowedState_debugBuildAnyChangeDebugApp_allowOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext) + .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1) + .addTargetSdkChangeWithId(TARGET_SDK, 2) + .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3) + .addEnabledChangeWithId(4) + .addDisabledChangeWithId(5).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .debuggable() + .withTargetSdk(TARGET_SDK) + .withPackageName(PACKAGE_NAME).build()); + + OverrideAllowedState stateTargetSdkLessChange = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkEqualChange = + overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkAfterChange = + overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME); + OverrideAllowedState stateEnabledChange = + overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME); + OverrideAllowedState stateDisabledChange = + overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME); + + assertThat(stateTargetSdkLessChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + assertThat(stateTargetSdkEqualChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + assertThat(stateTargetSdkAfterChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + assertThat(stateEnabledChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + assertThat(stateDisabledChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + } + + @Test + public void getOverrideAllowedState_debugBuildAnyChangeReleaseApp_allowOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(debuggableBuild(), mContext) + .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1) + .addTargetSdkChangeWithId(TARGET_SDK, 2) + .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3) + .addEnabledChangeWithId(4) + .addDisabledChangeWithId(5).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .withPackageName(PACKAGE_NAME) + .withTargetSdk(TARGET_SDK).build()); + + OverrideAllowedState stateTargetSdkLessChange = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkEqualChange = + overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkAfterChange = + overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME); + OverrideAllowedState stateEnabledChange = + overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME); + OverrideAllowedState stateDisabledChange = + overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME); + + assertThat(stateTargetSdkLessChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + assertThat(stateTargetSdkEqualChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + assertThat(stateTargetSdkAfterChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + assertThat(stateEnabledChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + assertThat(stateDisabledChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); + } + + @Test + public void getOverrideAllowedState_betaBuildTargetSdkChangeDebugApp_allowOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext) + .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1) + .addTargetSdkChangeWithId(TARGET_SDK, 2) + .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .debuggable() + .withTargetSdk(TARGET_SDK) + .withPackageName(PACKAGE_NAME).build()); + + OverrideAllowedState stateTargetSdkLessChange = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkEqualChange = + overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkAfterChange = + overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME); + + assertThat(stateTargetSdkLessChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_BEFORE)); + assertThat(stateTargetSdkEqualChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK)); + assertThat(stateTargetSdkAfterChange) + .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_AFTER)); + } + + @Test + public void getOverrideAllowedState_betaBuildEnabledChangeDebugApp_rejectOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext) + .addEnabledChangeWithId(1).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .withPackageName(PACKAGE_NAME) + .debuggable() + .build()); + + OverrideAllowedState allowedState = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + + assertThat(allowedState) + .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1)); + } + + @Test + public void getOverrideAllowedState_betaBuildDisabledChangeDebugApp_rejectOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext) + .addDisabledChangeWithId(1).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .debuggable() + .withPackageName(PACKAGE_NAME).build()); + + OverrideAllowedState allowedState = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + + assertThat(allowedState) + .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1)); + } + + @Test + public void getOverrideAllowedState_betaBuildAnyChangeReleaseApp_rejectOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext) + .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1) + .addTargetSdkChangeWithId(TARGET_SDK, 2) + .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3) + .addEnabledChangeWithId(4) + .addDisabledChangeWithId(5).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .withPackageName(PACKAGE_NAME) + .withTargetSdk(TARGET_SDK).build()); + + OverrideAllowedState stateTargetSdkLessChange = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkEqualChange = + overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkAfterChange = + overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME); + OverrideAllowedState stateEnabledChange = + overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME); + OverrideAllowedState stateDisabledChange = + overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME); + + assertThat(stateTargetSdkLessChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + assertThat(stateTargetSdkEqualChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + assertThat(stateTargetSdkAfterChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + assertThat(stateEnabledChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + assertThat(stateDisabledChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + } + + @Test + public void getOverrideAllowedState_finalBuildTargetSdkChangeDebugAppOptin_allowOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext) + .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 1).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .debuggable() + .withTargetSdk(TARGET_SDK) + .withPackageName(PACKAGE_NAME).build()); + + OverrideAllowedState allowedState = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + + assertThat(allowedState) + .isEqualTo(new OverrideAllowedState(ALLOWED, TARGET_SDK, TARGET_SDK_AFTER)); + } + + @Test + public void getOverrideAllowedState_finalBuildTargetSdkChangeDebugAppOptout_rejectOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext) + .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1) + .addTargetSdkChangeWithId(TARGET_SDK, 2).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .withPackageName(PACKAGE_NAME) + .withTargetSdk(TARGET_SDK) + .debuggable() + .build()); + + OverrideAllowedState stateTargetSdkLessChange = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkEqualChange = + overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME); + + assertThat(stateTargetSdkLessChange).isEqualTo( + new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, TARGET_SDK, + TARGET_SDK_BEFORE)); + assertThat(stateTargetSdkEqualChange).isEqualTo( + new OverrideAllowedState(DISABLED_TARGET_SDK_TOO_HIGH, TARGET_SDK, TARGET_SDK)); + } + + @Test + public void getOverrideAllowedState_finalBuildEnabledChangeDebugApp_rejectOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext) + .addEnabledChangeWithId(1).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .withPackageName(PACKAGE_NAME) + .debuggable().build()); + + OverrideAllowedState allowedState = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + + assertThat(allowedState) + .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1)); + } + + @Test + public void getOverrideAllowedState_finalBuildDisabledChangeDebugApp_rejectOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext) + .addDisabledChangeWithId(1).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .withPackageName(PACKAGE_NAME) + .debuggable().build()); + + OverrideAllowedState allowedState = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + + assertThat(allowedState) + .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1)); + } + + @Test + public void getOverrideAllowedState_finalBuildAnyChangeReleaseApp_rejectOverride() + throws Exception { + CompatConfig config = CompatConfigBuilder.create(finalBuild(), mContext) + .addTargetSdkChangeWithId(TARGET_SDK_BEFORE, 1) + .addTargetSdkChangeWithId(TARGET_SDK, 2) + .addTargetSdkChangeWithId(TARGET_SDK_AFTER, 3) + .addEnabledChangeWithId(4) + .addDisabledChangeWithId(5).build(); + IOverrideValidator overrideValidator = config.getOverrideValidator(); + when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt())) + .thenReturn(ApplicationInfoBuilder.create() + .withPackageName(PACKAGE_NAME) + .withTargetSdk(TARGET_SDK).build()); + + OverrideAllowedState stateTargetSdkLessChange = + overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkEqualChange = + overrideValidator.getOverrideAllowedState(2, PACKAGE_NAME); + OverrideAllowedState stateTargetSdkAfterChange = + overrideValidator.getOverrideAllowedState(3, PACKAGE_NAME); + OverrideAllowedState stateEnabledChange = + overrideValidator.getOverrideAllowedState(4, PACKAGE_NAME); + OverrideAllowedState stateDisabledChange = + overrideValidator.getOverrideAllowedState(5, PACKAGE_NAME); + + assertThat(stateTargetSdkLessChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + assertThat(stateTargetSdkEqualChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + assertThat(stateTargetSdkAfterChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + assertThat(stateEnabledChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + assertThat(stateDisabledChange) + .isEqualTo(new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java index c406876c5cee..ce5d6d9be770 100644 --- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java @@ -26,21 +26,20 @@ import static org.mockito.Mockito.when; import static org.mockito.internal.verification.VerificationModeFactory.times; import static org.testng.Assert.assertThrows; -import android.compat.Compatibility; import android.content.Context; import android.content.pm.PackageManager; -import com.android.internal.compat.CompatibilityChangeConfig; +import androidx.test.runner.AndroidJUnit4; -import com.google.common.collect.ImmutableSet; +import com.android.internal.compat.AndroidBuildClassifier; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.MockitoAnnotations; -@RunWith(MockitoJUnitRunner.class) +@RunWith(AndroidJUnit4.class) public class PlatformCompatTest { private static final String PACKAGE_NAME = "my.package"; @@ -50,84 +49,77 @@ public class PlatformCompatTest { private PackageManager mPackageManager; @Mock CompatChange.ChangeListener mListener1, mListener2; - + PlatformCompat mPlatformCompat; + CompatConfig mCompatConfig; + @Mock + private AndroidBuildClassifier mBuildClassifier; @Before public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getPackageUid(eq(PACKAGE_NAME), eq(0))).thenThrow( new PackageManager.NameNotFoundException()); - CompatConfig.get().clearChanges(); + mCompatConfig = new CompatConfig(mBuildClassifier, mContext); + mPlatformCompat = new PlatformCompat(mContext, mCompatConfig); + // Assume userdebug/eng non-final build + when(mBuildClassifier.isDebuggableBuild()).thenReturn(true); + when(mBuildClassifier.isFinalBuild()).thenReturn(false); } @Test - public void testRegisterListenerToSameIdThrows() { - PlatformCompat pc = new PlatformCompat(mContext); - + public void testRegisterListenerToSameIdThrows() throws Exception { // Registering a listener to change 1 is successful. - pc.registerListener(1, mListener1); + mPlatformCompat.registerListener(1, mListener1); // Registering a listener to change 2 is successful. - pc.registerListener(2, mListener1); + mPlatformCompat.registerListener(2, mListener1); // Trying to register another listener to change id 1 fails. - assertThrows(IllegalStateException.class, () -> pc.registerListener(1, mListener1)); + assertThrows(IllegalStateException.class, + () -> mPlatformCompat.registerListener(1, mListener1)); } @Test - public void testRegisterListenerReturn() { - PlatformCompat pc = new PlatformCompat(mContext); - - pc.setOverrides( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())), + public void testRegisterListenerReturn() throws Exception { + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).build(), PACKAGE_NAME); // Change id 1 is known (added in setOverrides). - assertThat(pc.registerListener(1, mListener1)).isTrue(); + assertThat(mPlatformCompat.registerListener(1, mListener1)).isTrue(); // Change 2 is unknown. - assertThat(pc.registerListener(2, mListener1)).isFalse(); + assertThat(mPlatformCompat.registerListener(2, mListener1)).isFalse(); } @Test - public void testListenerCalledOnSetOverrides() { - PlatformCompat pc = new PlatformCompat(mContext); + public void testListenerCalledOnSetOverrides() throws Exception { + mPlatformCompat.registerListener(1, mListener1); + mPlatformCompat.registerListener(2, mListener1); - pc.registerListener(1, mListener1); - pc.registerListener(2, mListener1); - - pc.setOverrides( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(), PACKAGE_NAME); verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME); } @Test - public void testListenerNotCalledOnWrongPackage() { - PlatformCompat pc = new PlatformCompat(mContext); - - pc.registerListener(1, mListener1); - pc.registerListener(2, mListener1); + public void testListenerNotCalledOnWrongPackage() throws Exception { + mPlatformCompat.registerListener(1, mListener1); + mPlatformCompat.registerListener(2, mListener1); - pc.setOverridesForTest( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(), PACKAGE_NAME); verify(mListener1, never()).onCompatChange("other.package"); } @Test - public void testListenerCalledOnSetOverridesTwoListeners() { - PlatformCompat pc = new PlatformCompat(mContext); - pc.registerListener(1, mListener1); + public void testListenerCalledOnSetOverridesTwoListeners() throws Exception { + mPlatformCompat.registerListener(1, mListener1); - final ImmutableSet<Long> enabled = ImmutableSet.of(1L); - final ImmutableSet<Long> disabled = ImmutableSet.of(2L); - - pc.setOverrides( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(enabled, disabled)), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(), PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); @@ -136,11 +128,10 @@ public class PlatformCompatTest { reset(mListener1); reset(mListener2); - pc.registerListener(2, mListener2); + mPlatformCompat.registerListener(2, mListener2); - pc.setOverrides( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(enabled, disabled)), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(), PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); @@ -148,31 +139,23 @@ public class PlatformCompatTest { } @Test - public void testListenerCalledOnSetOverridesForTest() { - PlatformCompat pc = new PlatformCompat(mContext); - - pc.registerListener(1, mListener1); - pc.registerListener(2, mListener1); + public void testListenerCalledOnSetOverridesForTest() throws Exception { + mPlatformCompat.registerListener(1, mListener1); + mPlatformCompat.registerListener(2, mListener1); - pc.setOverridesForTest( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(), PACKAGE_NAME); verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME); } @Test - public void testListenerCalledOnSetOverridesTwoListenersForTest() { - PlatformCompat pc = new PlatformCompat(mContext); - pc.registerListener(1, mListener1); + public void testListenerCalledOnSetOverridesTwoListenersForTest() throws Exception { + mPlatformCompat.registerListener(1, mListener1); - final ImmutableSet<Long> enabled = ImmutableSet.of(1L); - final ImmutableSet<Long> disabled = ImmutableSet.of(2L); - - pc.setOverridesForTest( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(enabled, disabled)), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(), PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); @@ -181,10 +164,10 @@ public class PlatformCompatTest { reset(mListener1); reset(mListener2); - pc.registerListener(2, mListener2); - pc.setOverridesForTest( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(enabled, disabled)), + mPlatformCompat.registerListener(2, mListener2); + + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(), PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); @@ -192,15 +175,12 @@ public class PlatformCompatTest { } @Test - public void testListenerCalledOnClearOverrides() { - PlatformCompat pc = new PlatformCompat(mContext); + public void testListenerCalledOnClearOverrides() throws Exception { + mPlatformCompat.registerListener(1, mListener1); + mPlatformCompat.registerListener(2, mListener2); - pc.registerListener(1, mListener1); - pc.registerListener(2, mListener2); - - pc.setOverrides( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).build(), PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); verify(mListener2, never()).onCompatChange(PACKAGE_NAME); @@ -208,21 +188,18 @@ public class PlatformCompatTest { reset(mListener1); reset(mListener2); - pc.clearOverrides(PACKAGE_NAME); + mPlatformCompat.clearOverrides(PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); verify(mListener2, never()).onCompatChange(PACKAGE_NAME); } @Test - public void testListenerCalledOnClearOverridesMultipleOverrides() { - PlatformCompat pc = new PlatformCompat(mContext); - - pc.registerListener(1, mListener1); - pc.registerListener(2, mListener2); + public void testListenerCalledOnClearOverridesMultipleOverrides() throws Exception { + mPlatformCompat.registerListener(1, mListener1); + mPlatformCompat.registerListener(2, mListener2); - pc.setOverrides( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(), PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME); @@ -230,21 +207,18 @@ public class PlatformCompatTest { reset(mListener1); reset(mListener2); - pc.clearOverrides(PACKAGE_NAME); + mPlatformCompat.clearOverrides(PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME); } @Test - public void testListenerCalledOnClearOverrideExists() { - PlatformCompat pc = new PlatformCompat(mContext); + public void testListenerCalledOnClearOverrideExists() throws Exception { + mPlatformCompat.registerListener(1, mListener1); + mPlatformCompat.registerListener(2, mListener2); - pc.registerListener(1, mListener1); - pc.registerListener(2, mListener2); - - pc.setOverrides( - new CompatibilityChangeConfig( - new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())), + mPlatformCompat.setOverrides( + CompatibilityChangeConfigBuilder.create().enable(1L).build(), PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); verify(mListener2, never()).onCompatChange(PACKAGE_NAME); @@ -252,21 +226,17 @@ public class PlatformCompatTest { reset(mListener1); reset(mListener2); - pc.clearOverride(1, PACKAGE_NAME); + mPlatformCompat.clearOverride(1, PACKAGE_NAME); verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME); verify(mListener2, never()).onCompatChange(PACKAGE_NAME); } @Test - public void testListenerCalledOnClearOverrideDoesntExist() { - PlatformCompat pc = new PlatformCompat(mContext); - - pc.registerListener(1, mListener1); + public void testListenerCalledOnClearOverrideDoesntExist() throws Exception { + mPlatformCompat.registerListener(1, mListener1); - pc.clearOverride(1, PACKAGE_NAME); + mPlatformCompat.clearOverride(1, PACKAGE_NAME); // Listener not called when a non existing override is removed. verify(mListener1, never()).onCompatChange(PACKAGE_NAME); } - - } 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 3456cc361eb4..71b568cc06c5 100644 --- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java @@ -29,6 +29,7 @@ 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; @@ -143,6 +144,36 @@ public class TimeDetectorServiceTest { 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)) @@ -180,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; @@ -205,6 +242,12 @@ public class TimeDetectorServiceTest { } @Override + public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) { + resetCallTracking(); + mLastNetworkSuggestion = timeSuggestion; + } + + @Override public void handleAutoTimeDetectionChanged() { resetCallTracking(); mLastAutoTimeDetectionToggleCalled = true; @@ -219,6 +262,7 @@ public class TimeDetectorServiceTest { void resetCallTracking() { mLastPhoneSuggestion = null; mLastManualSuggestion = null; + mLastNetworkSuggestion = null; mLastAutoTimeDetectionToggleCalled = false; mDumpCalled = false; } @@ -231,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/telephony/OWNERS b/telephony/OWNERS index 2a6e8deeb13e..58a7ea08da3f 100644 --- a/telephony/OWNERS +++ b/telephony/OWNERS @@ -14,4 +14,5 @@ shuoq@google.com refuhoo@google.com paulye@google.com nazaninb@google.com -sarahchin@google.com
\ No newline at end of file +sarahchin@google.com +dbright@google.com diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java index d4526a48fdb1..825ce2fc1a00 100644 --- a/telephony/java/android/telephony/LocationAccessPolicy.java +++ b/telephony/common/android/telephony/LocationAccessPolicy.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2020 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. @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package android.telephony; @@ -59,6 +59,7 @@ public final class LocationAccessPolicy { DENIED_HARD, } + /** Data structure for location permission query */ public static class LocationPermissionQuery { public final String callingPackage; public final int callingUid; @@ -80,6 +81,7 @@ public final class LocationAccessPolicy { this.method = method; } + /** Builder for LocationPermissionQuery */ public static class Builder { private String mCallingPackage; private int mCallingUid; @@ -149,6 +151,7 @@ public final class LocationAccessPolicy { return this; } + /** build LocationPermissionQuery */ public LocationPermissionQuery build() { return new LocationPermissionQuery(mCallingPackage, mCallingUid, mCallingPid, mMinSdkVersionForCoarse, mMinSdkVersionForFine, @@ -235,6 +238,7 @@ public final class LocationAccessPolicy { } } + /** Check if location permissions have been granted */ public static LocationPermissionResult checkLocationPermission( Context context, LocationPermissionQuery query) { // Always allow the phone process and system server to access location. This avoid @@ -341,4 +345,4 @@ public final class LocationAccessPolicy { } return false; } -}
\ No newline at end of file +} diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java index 0630454cbf53..b5d33699a7f6 100644 --- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java +++ b/telephony/common/com/android/internal/telephony/CarrierAppUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Android Open Source Project + * Copyright (C) 2020 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. @@ -11,7 +11,7 @@ * 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 + * limitations under the License. */ package com.android.internal.telephony; @@ -73,7 +73,7 @@ public final class CarrierAppUtils { * system startup prior to any application running, as well as any time the set of carrier * privileged apps may have changed. */ - public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage, + public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage, IPackageManager packageManager, TelephonyManager telephonyManager, ContentResolver contentResolver, int userId) { if (DEBUG) { @@ -100,7 +100,7 @@ public final class CarrierAppUtils { * broadcasts. The app will continue to run (briefly) after being disabled, before the Package * Manager can kill it, and this can lead to crashes as the app is in an unexpected state. */ - public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage, + public static synchronized void disableCarrierAppsUntilPrivileged(String callingPackage, IPackageManager packageManager, ContentResolver contentResolver, int userId) { if (DEBUG) { Slog.d(TAG, "disableCarrierAppsUntilPrivileged"); @@ -117,7 +117,10 @@ public final class CarrierAppUtils { systemCarrierAppsDisabledUntilUsed, systemCarrierAssociatedAppsDisabledUntilUsed); } - // Must be public b/c framework unit tests can't access package-private methods. + /** + * Disable carrier apps until they are privileged + * Must be public b/c framework unit tests can't access package-private methods. + */ @VisibleForTesting public static void disableCarrierAppsUntilPrivileged(String callingPackage, IPackageManager packageManager, @Nullable TelephonyManager telephonyManager, @@ -166,10 +169,10 @@ public final class CarrierAppUtils { // Only update enabled state for the app on /system. Once it has been // updated we shouldn't touch it. if (!ai.isUpdatedSystemApp() - && (ai.enabledSetting == - PackageManager.COMPONENT_ENABLED_STATE_DEFAULT - || ai.enabledSetting == - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED + && (ai.enabledSetting + == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT + || ai.enabledSetting + == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED || (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0)) { Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user " + userId); @@ -188,10 +191,10 @@ public final class CarrierAppUtils { // Also enable any associated apps for this carrier app. if (associatedAppList != null) { for (ApplicationInfo associatedApp : associatedAppList) { - if (associatedApp.enabledSetting == - PackageManager.COMPONENT_ENABLED_STATE_DEFAULT - || associatedApp.enabledSetting == - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED + if (associatedApp.enabledSetting + == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT + || associatedApp.enabledSetting + == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED || (associatedApp.flags & ApplicationInfo.FLAG_INSTALLED) == 0) { Slog.i(TAG, "Update associated state(" + associatedApp.packageName @@ -216,8 +219,8 @@ public final class CarrierAppUtils { // Only update enabled state for the app on /system. Once it has been // updated we shouldn't touch it. if (!ai.isUpdatedSystemApp() - && ai.enabledSetting == - PackageManager.COMPONENT_ENABLED_STATE_DEFAULT + && ai.enabledSetting + == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) { Slog.i(TAG, "Update state(" + packageName + "): DISABLED_UNTIL_USED for user " + userId); @@ -291,8 +294,8 @@ public final class CarrierAppUtils { ApplicationInfo ai = candidates.get(i); String packageName = ai.packageName; boolean hasPrivileges = - telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) == - TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; + telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; if (!hasPrivileges) { candidates.remove(i); } diff --git a/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java b/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java index 922af126e73e..0b47547d3b0c 100644 --- a/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java +++ b/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java @@ -24,17 +24,17 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.Handler; +import android.os.HandlerThread; import android.os.Looper; import android.os.UserHandle; -import com.android.internal.os.BackgroundThread; - /** * Helper class for monitoring the state of packages: adding, removing, * updating, and disappearing and reappearing on the SD card. */ public abstract class PackageChangeReceiver extends BroadcastReceiver { static final IntentFilter sPackageIntentFilter = new IntentFilter(); + private static HandlerThread sHandlerThread; static { sPackageIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); sPackageIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); @@ -43,28 +43,24 @@ public abstract class PackageChangeReceiver extends BroadcastReceiver { sPackageIntentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); sPackageIntentFilter.addDataScheme("package"); } + // Keep an instance of Context around as long as we still want the receiver: + // if the instance of Context gets garbage-collected, it'll unregister the receiver, so only + // unset when we want to unregister. Context mRegisteredContext; /** - * To register the intents that needed for monitoring the state of packages + * To register the intents that needed for monitoring the state of packages. Once this method + * has been called on an instance of {@link PackageChangeReceiver}, all subsequent calls must + * have the same {@code user} argument. */ public void register(@NonNull Context context, @Nullable Looper thread, @Nullable UserHandle user) { if (mRegisteredContext != null) { throw new IllegalStateException("Already registered"); } - Handler handler = (thread == null) ? BackgroundThread.getHandler() : new Handler(thread); - mRegisteredContext = context; - if (handler != null) { - if (user != null) { - context.registerReceiverAsUser(this, user, sPackageIntentFilter, null, handler); - } else { - context.registerReceiver(this, sPackageIntentFilter, - null, handler); - } - } else { - throw new NullPointerException(); - } + Handler handler = new Handler(thread == null ? getStaticLooper() : thread); + mRegisteredContext = user == null ? context : context.createContextAsUser(user, 0); + mRegisteredContext.registerReceiver(this, sPackageIntentFilter, null, handler); } /** @@ -78,6 +74,14 @@ public abstract class PackageChangeReceiver extends BroadcastReceiver { mRegisteredContext = null; } + private static synchronized Looper getStaticLooper() { + if (sHandlerThread == null) { + sHandlerThread = new HandlerThread(PackageChangeReceiver.class.getSimpleName()); + sHandlerThread.start(); + } + return sHandlerThread.getLooper(); + } + /** * This method is invoked when receive the Intent.ACTION_PACKAGE_ADDED */ diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java index 07dfcf09b1c5..53842cdeea5a 100644 --- a/telephony/common/com/android/internal/telephony/SmsApplication.java +++ b/telephony/common/com/android/internal/telephony/SmsApplication.java @@ -58,7 +58,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; - +import java.util.stream.Collectors; /** @@ -250,6 +250,7 @@ public final class SmsApplication { private static Collection<SmsApplicationData> getApplicationCollectionInternal( Context context, int userId) { PackageManager packageManager = context.getPackageManager(); + UserHandle userHandle = UserHandle.of(userId); // Get the list of apps registered for SMS Intent intent = new Intent(Intents.SMS_DELIVER_ACTION); @@ -258,7 +259,7 @@ public final class SmsApplication { } List<ResolveInfo> smsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, - userId); + userHandle); HashMap<String, SmsApplicationData> receivers = new HashMap<String, SmsApplicationData>(); @@ -285,7 +286,7 @@ public final class SmsApplication { intent.setDataAndType(null, "application/vnd.wap.mms-message"); List<ResolveInfo> mmsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, - userId); + userHandle); for (ResolveInfo resolveInfo : mmsReceivers) { final ActivityInfo activityInfo = resolveInfo.activityInfo; if (activityInfo == null) { @@ -327,7 +328,7 @@ public final class SmsApplication { Uri.fromParts(SCHEME_SMSTO, "", null)); List<ResolveInfo> sendToActivities = packageManager.queryIntentActivitiesAsUser(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, - userId); + userHandle); for (ResolveInfo resolveInfo : sendToActivities) { final ActivityInfo activityInfo = resolveInfo.activityInfo; if (activityInfo == null) { @@ -345,7 +346,7 @@ public final class SmsApplication { List<ResolveInfo> smsAppChangedReceivers = packageManager.queryBroadcastReceiversAsUser(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle); if (DEBUG_MULTIUSER) { Log.i(LOG_TAG, "getApplicationCollectionInternal smsAppChangedActivities=" + smsAppChangedReceivers); @@ -372,7 +373,7 @@ public final class SmsApplication { List<ResolveInfo> providerChangedReceivers = packageManager.queryBroadcastReceiversAsUser(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle); if (DEBUG_MULTIUSER) { Log.i(LOG_TAG, "getApplicationCollectionInternal providerChangedActivities=" + providerChangedReceivers); @@ -399,7 +400,7 @@ public final class SmsApplication { List<ResolveInfo> simFullReceivers = packageManager.queryBroadcastReceiversAsUser(intent, PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle); if (DEBUG_MULTIUSER) { Log.i(LOG_TAG, "getApplicationCollectionInternal simFullReceivers=" + simFullReceivers); @@ -631,7 +632,8 @@ public final class SmsApplication { } // We only make the change if the new package is valid - PackageManager packageManager = context.getPackageManager(); + PackageManager packageManager = + context.createContextAsUser(userHandle, 0).getPackageManager(); Collection<SmsApplicationData> applications = getApplicationCollectionInternal( context, userId); SmsApplicationData oldAppData = oldPackageName != null ? @@ -642,8 +644,7 @@ public final class SmsApplication { AppOpsManager appOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); if (oldPackageName != null) { try { - int uid = packageManager.getPackageInfoAsUser( - oldPackageName, 0, userId).applicationInfo.uid; + int uid = packageManager.getPackageInfo(oldPackageName, 0).applicationInfo.uid; setExclusiveAppops(oldPackageName, appOps, uid, AppOpsManager.MODE_DEFAULT); } catch (NameNotFoundException e) { Rlog.w(LOG_TAG, "Old SMS package not found: " + oldPackageName); @@ -807,9 +808,16 @@ public final class SmsApplication { } private void onPackageChanged() { - PackageManager packageManager = mContext.getPackageManager(); + int userId; + try { + userId = getSendingUser().getIdentifier(); + } catch (NullPointerException e) { + // This should never happen in prod -- unit tests will put the receiver into a + // unusual state where the pending result is null, which produces a NPE when calling + // getSendingUserId. Just pretend like it's the system user for testing. + userId = UserHandle.USER_SYSTEM; + } Context userContext = mContext; - final int userId = getSendingUserId(); if (userId != UserHandle.USER_SYSTEM) { try { userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0, @@ -820,10 +828,11 @@ public final class SmsApplication { } } } + PackageManager packageManager = userContext.getPackageManager(); // Ensure this component is still configured as the preferred activity ComponentName componentName = getDefaultSendToApplication(userContext, true); if (componentName != null) { - configurePreferredActivity(packageManager, componentName, userId); + configurePreferredActivity(packageManager, componentName); } } } @@ -835,41 +844,36 @@ public final class SmsApplication { @UnsupportedAppUsage private static void configurePreferredActivity(PackageManager packageManager, - ComponentName componentName, int userId) { + ComponentName componentName) { // Add the four activity preferences we want to direct to this app. - replacePreferredActivity(packageManager, componentName, userId, SCHEME_SMS); - replacePreferredActivity(packageManager, componentName, userId, SCHEME_SMSTO); - replacePreferredActivity(packageManager, componentName, userId, SCHEME_MMS); - replacePreferredActivity(packageManager, componentName, userId, SCHEME_MMSTO); + replacePreferredActivity(packageManager, componentName, SCHEME_SMS); + replacePreferredActivity(packageManager, componentName, SCHEME_SMSTO); + replacePreferredActivity(packageManager, componentName, SCHEME_MMS); + replacePreferredActivity(packageManager, componentName, SCHEME_MMSTO); } /** * Updates the ACTION_SENDTO activity to the specified component for the specified scheme. */ private static void replacePreferredActivity(PackageManager packageManager, - ComponentName componentName, int userId, String scheme) { + ComponentName componentName, String scheme) { // Build the set of existing activities that handle this scheme Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts(scheme, "", null)); - List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivitiesAsUser( - intent, PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_RESOLVED_FILTER, - userId); + List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities( + intent, PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_RESOLVED_FILTER); - // Build the set of ComponentNames for these activities - final int n = resolveInfoList.size(); - ComponentName[] set = new ComponentName[n]; - for (int i = 0; i < n; i++) { - ResolveInfo info = resolveInfoList.get(i); - set[i] = new ComponentName(info.activityInfo.packageName, info.activityInfo.name); - } + List<ComponentName> components = resolveInfoList.stream().map(info -> + new ComponentName(info.activityInfo.packageName, info.activityInfo.name)) + .collect(Collectors.toList()); // Update the preferred SENDTO activity for the specified scheme IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_SENDTO); intentFilter.addCategory(Intent.CATEGORY_DEFAULT); intentFilter.addDataScheme(scheme); - packageManager.replacePreferredActivityAsUser(intentFilter, + packageManager.replacePreferredActivity(intentFilter, IntentFilter.MATCH_CATEGORY_SCHEME + IntentFilter.MATCH_ADJUSTMENT_NORMAL, - set, componentName, userId); + components, componentName); } /** diff --git a/telephony/java/com/android/internal/telephony/util/ArrayUtils.java b/telephony/common/com/android/internal/telephony/util/ArrayUtils.java index 2905125c69cc..28401a6a7092 100644 --- a/telephony/java/com/android/internal/telephony/util/ArrayUtils.java +++ b/telephony/common/com/android/internal/telephony/util/ArrayUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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. @@ -29,17 +29,30 @@ public final class ArrayUtils { /** * Adds value to given array if not already present, providing set-like behavior. + * + * @param kind The class of the array elements. + * @param array The array to append to. + * @param element The array element to append. + * @return The array containing the appended element. */ @SuppressWarnings("unchecked") - public static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element) { + @NonNull + public static <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element) { return appendElement(kind, array, element, false); } /** * Adds value to given array. + * + * @param kind The class of the array elements. + * @param array The array to append to. + * @param element The array element to append. + * @param allowDuplicates Whether to allow duplicated elements in array. + * @return The array containing the appended element. */ @SuppressWarnings("unchecked") - public static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element, + @NonNull + public static <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element, boolean allowDuplicates) { final T[] result; final int end; @@ -59,13 +72,14 @@ public final class ArrayUtils { /** * Combine multiple arrays into a single array. * - * @param kind The class of the array elements + * @param kind The class of the array elements * @param arrays The arrays to combine - * @param <T> The class of the array elements (inferred from kind). + * @param <T> The class of the array elements (inferred from kind). * @return A single array containing all the elements of the parameter arrays. */ @SuppressWarnings("unchecked") - public static @NonNull <T> T[] concatElements(Class<T> kind, @Nullable T[]... arrays) { + @NonNull + public static <T> T[] concatElements(Class<T> kind, @Nullable T[]... arrays) { if (arrays == null || arrays.length == 0) { return createEmptyArray(kind); } diff --git a/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java index 0498d7c31406..0498d7c31406 100644 --- a/telephony/java/com/android/internal/telephony/util/TelephonyUtils.java +++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 1014571bc41a..a3044edd1631 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -64,6 +64,13 @@ public class ServiceState implements Parcelable { static final boolean DBG = false; static final boolean VDBG = false; // STOPSHIP if true + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "STATE_", + value = {STATE_IN_SERVICE, STATE_OUT_OF_SERVICE, STATE_EMERGENCY_ONLY, + STATE_POWER_OFF}) + public @interface RegState {} + /** * Normal operation condition, the phone is registered * with an operator either in home network or in roaming. @@ -82,6 +89,7 @@ public class ServiceState implements Parcelable { /** * The phone is registered and locked. Only emergency numbers are allowed. {@more} */ + //TODO: This state is not used anymore. It should be deprecated in a future release. public static final int STATE_EMERGENCY_ONLY = TelephonyProtoEnums.SERVICE_STATE_EMERGENCY_ONLY; // 2 @@ -530,13 +538,15 @@ public class ServiceState implements Parcelable { } /** - * Get current data service state + * Get current data registration state. * * @see #STATE_IN_SERVICE * @see #STATE_OUT_OF_SERVICE * @see #STATE_EMERGENCY_ONLY * @see #STATE_POWER_OFF * + * @return current data registration state + * * @hide */ @UnsupportedAppUsage @@ -545,6 +555,23 @@ public class ServiceState implements Parcelable { } /** + * Get current data registration state. + * + * @see #STATE_IN_SERVICE + * @see #STATE_OUT_OF_SERVICE + * @see #STATE_EMERGENCY_ONLY + * @see #STATE_POWER_OFF + * + * @return current data registration state + * + * @hide + */ + @SystemApi + public @RegState int getDataRegistrationState() { + return getDataRegState(); + } + + /** * Get the current duplex mode * * @see #DUPLEX_MODE_UNKNOWN @@ -1437,7 +1464,15 @@ public class ServiceState implements Parcelable { return getRilDataRadioTechnology(); } - /** @hide */ + /** + * Transform RIL radio technology {@link RilRadioTechnology} value to Network + * type {@link NetworkType}. + * + * @param rat The RIL radio technology {@link RilRadioTechnology}. + * @return The network type {@link NetworkType}. + * + * @hide + */ public static int rilRadioTechnologyToNetworkType(@RilRadioTechnology int rat) { switch(rat) { case RIL_RADIO_TECHNOLOGY_GPRS: @@ -1519,7 +1554,15 @@ public class ServiceState implements Parcelable { } } - /** @hide */ + /** + * Transform network type {@link NetworkType} value to RIL radio technology + * {@link RilRadioTechnology}. + * + * @param networkType The network type {@link NetworkType}. + * @return The RIL radio technology {@link RilRadioTechnology}. + * + * @hide + */ public static int networkTypeToRilRadioTechnology(int networkType) { switch(networkType) { case TelephonyManager.NETWORK_TYPE_GPRS: @@ -1720,7 +1763,14 @@ public class ServiceState implements Parcelable { return bearerBitmask; } - /** @hide */ + /** + * Convert network type bitmask to bearer bitmask. + * + * @param networkTypeBitmask The network type bitmask value + * @return The bearer bitmask value. + * + * @hide + */ public static int convertNetworkTypeBitmaskToBearerBitmask(int networkTypeBitmask) { if (networkTypeBitmask == 0) { return 0; @@ -1734,7 +1784,14 @@ public class ServiceState implements Parcelable { return bearerBitmask; } - /** @hide */ + /** + * Convert bearer bitmask to network type bitmask. + * + * @param bearerBitmask The bearer bitmask value. + * @return The network type bitmask value. + * + * @hide + */ public static int convertBearerBitmaskToNetworkTypeBitmask(int bearerBitmask) { if (bearerBitmask == 0) { return 0; @@ -1893,9 +1950,18 @@ public class ServiceState implements Parcelable { * Returns a copy of self with location-identifying information removed. * Always clears the NetworkRegistrationInfo's CellIdentity fields, but if removeCoarseLocation * is true, clears other info as well. + * + * @param removeCoarseLocation Whether to also remove coarse location information. + * if false, it only clears fine location information such as + * NetworkRegistrationInfo's CellIdentity fields; If true, it will + * also remove other location information such as operator's MCC + * and MNC. + * @return the copied ServiceState with location info sanitized. * @hide */ - public ServiceState sanitizeLocationInfo(boolean removeCoarseLocation) { + @SystemApi + @NonNull + public ServiceState createLocationInfoSanitizedCopy(boolean removeCoarseLocation) { ServiceState state = new ServiceState(this); synchronized (state.mNetworkRegistrationInfos) { List<NetworkRegistrationInfo> networkRegistrationInfos = diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 376a5e00ae97..15c1807cd532 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; @@ -1197,12 +1197,17 @@ public class SubscriptionManager { } /** - * Get the active SubscriptionInfo associated with the iccId + * Gets an active SubscriptionInfo {@link SubscriptionInfo} associated with the Sim IccId. + * * @param iccId the IccId of SIM card * @return SubscriptionInfo, maybe null if its not active + * * @hide */ - public SubscriptionInfo getActiveSubscriptionInfoForIccIndex(String iccId) { + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @Nullable + @SystemApi + public SubscriptionInfo getActiveSubscriptionInfoForIcc(@NonNull String iccId) { if (VDBG) logd("[getActiveSubscriptionInfoForIccIndex]+ iccId=" + iccId); if (iccId == null) { logd("[getActiveSubscriptionInfoForIccIndex]- null iccid"); @@ -2645,8 +2650,7 @@ public class SubscriptionManager { /** * Checks whether the app with the given context is authorized to manage the given subscription - * according to its metadata. Only supported for embedded subscriptions (if - * {@code SubscriptionInfo#isEmbedded} returns true). + * according to its metadata. * * @param info The subscription to check. * @return whether the app is authorized to manage this subscription per its metadata. @@ -2659,16 +2663,16 @@ public class SubscriptionManager { * Checks whether the given app is authorized to manage the given subscription. An app can only * be authorized if it is included in the {@link android.telephony.UiccAccessRule} of the * {@link android.telephony.SubscriptionInfo} with the access status. - * Only supported for embedded subscriptions (if {@link SubscriptionInfo#isEmbedded} - * returns true). * * @param info The subscription to check. * @param packageName Package name of the app to check. * @return whether the app is authorized to manage this subscription per its access rules. * @hide */ - public boolean canManageSubscription(SubscriptionInfo info, String packageName) { - if (info == null || info.getAllAccessRules() == null) { + @SystemApi + public boolean canManageSubscription(@Nullable SubscriptionInfo info, + @Nullable String packageName) { + if (info == null || info.getAllAccessRules() == null || packageName == null) { return false; } PackageManager packageManager = mContext.getPackageManager(); @@ -3163,6 +3167,34 @@ public class SubscriptionManager { } /** + * Set uicc applications being enabled or disabled. + * The value will be remembered on the subscription and will be applied whenever it's present. + * If the subscription in currently present, it will also apply the setting to modem + * immediately. + * + * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required + * + * @param enabled whether uicc applications are enabled or disabled. + * @param subscriptionId which subscription to operate on. + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + public void setUiccApplicationsEnabled(boolean enabled, int subscriptionId) { + if (VDBG) { + logd("setUiccApplicationsEnabled subId= " + subscriptionId + " enable " + enabled); + } + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + iSub.setUiccApplicationsEnabled(enabled, subscriptionId); + } + } catch (RemoteException ex) { + // ignore it + } + } + + /** * Whether it's supported to disable / re-enable a subscription on a physical (non-euicc) SIM. * * Physical SIM refers non-euicc, or aka non-programmable SIM. diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 87bdaa9a9fe4..b8ce32f79c34 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -769,30 +769,6 @@ public class TelephonyManager { public static final String EXTRA_PRECISE_DISCONNECT_CAUSE = "precise_disconnect_cause"; /** - * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast - * for an String containing the data APN type. - * - * <p class="note"> - * Retrieve with - * {@link android.content.Intent#getStringExtra(String name)}. - * - * @hide - */ - public static final String EXTRA_DATA_APN_TYPE = PhoneConstants.DATA_APN_TYPE_KEY; - - /** - * The lookup key used with the {@link #ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED} broadcast - * for an String containing the data APN. - * - * <p class="note"> - * Retrieve with - * {@link android.content.Intent#getStringExtra(String name)}. - * - * @hide - */ - public static final String EXTRA_DATA_APN = PhoneConstants.DATA_APN_KEY; - - /** * Broadcast intent action for letting the default dialer to know to show voicemail * notification. * diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 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/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index 92aab4b12330..5a26232c8892 100755 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -285,4 +285,6 @@ interface ISub { int getActiveDataSubscriptionId(); boolean canDisablePhysicalSubscription(); + + int setUiccApplicationsEnabled(boolean enabled, int subscriptionId); } 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 index 16189c8e0ac8..61c3829e68a1 100644 --- a/tests/TelephonyCommonTests/Android.bp +++ b/tests/TelephonyCommonTests/Android.bp @@ -38,7 +38,7 @@ android_test { // Uncomment this and comment out the jarjar rule if you want to attach a debugger and step // through the renamed classes. - //platform_apis: true, + // platform_apis: true, libs: [ "android.test.runner", diff --git a/tests/TelephonyCommonTests/jarjar-rules.txt b/tests/TelephonyCommonTests/jarjar-rules.txt index fe3471973c6e..4d1115f3c56c 100644 --- a/tests/TelephonyCommonTests/jarjar-rules.txt +++ b/tests/TelephonyCommonTests/jarjar-rules.txt @@ -1 +1,3 @@ rule com.android.internal.telephony.SmsApplication* com.android.internal.telephony.tests.SmsApplication@1 +rule android.telephony.PackageChangeReceiver* com.android.internal.telephony.tests.PackageChangeReceiver@1 +rule com.android.internal.os.BackgroundThread* com.android.internal.telephony.tests.BackgroundThread@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 index 6d0ee1891ac9..83fd20803ed8 100644 --- a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java +++ b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java @@ -17,26 +17,34 @@ package com.android.internal.telephony.tests; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNotNull; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.times; 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.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; 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.net.Uri; +import android.os.Handler; import android.os.UserHandle; import android.provider.Telephony; import android.telephony.TelephonyManager; @@ -48,11 +56,15 @@ import com.android.internal.telephony.SmsApplication; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; /** * Unit tests for the {@link SmsApplication} utility class @@ -80,6 +92,13 @@ public class SmsApplicationTest { AppOpsManager.OPSTR_READ_CELL_BROADCASTS }; + private static final Set<String> SCHEMES_FOR_PREFERRED_APP = Arrays.stream(new String[]{ + "mms", + "mmsto", + "sms", + "smsto" + }).collect(Collectors.toSet()); + @Mock private Context mContext; @Mock private TelephonyManager mTelephonyManager; @Mock private RoleManager mRoleManager; @@ -94,13 +113,16 @@ public class SmsApplicationTest { when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mContext.getSystemService(RoleManager.class)).thenReturn(mRoleManager); when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOpsManager); + when(mContext.createContextAsUser(isNotNull(), anyInt())).thenReturn(mContext); doAnswer(invocation -> getResolveInfosForIntent(invocation.getArgument(0))) .when(mPackageManager) - .queryBroadcastReceiversAsUser(nullable(Intent.class), anyInt(), anyInt()); + .queryBroadcastReceiversAsUser(nullable(Intent.class), anyInt(), + nullable(UserHandle.class)); doAnswer(invocation -> getResolveInfosForIntent(invocation.getArgument(0))) .when(mPackageManager) - .queryIntentActivitiesAsUser(nullable(Intent.class), anyInt(), anyInt()); + .queryIntentActivitiesAsUser(nullable(Intent.class), anyInt(), + nullable(UserHandle.class)); doAnswer(invocation -> getResolveInfosForIntent(invocation.getArgument(0))) .when(mPackageManager) .queryIntentServicesAsUser(nullable(Intent.class), anyInt(), @@ -137,6 +159,37 @@ public class SmsApplicationTest { AppOpsManager.MODE_ALLOWED); } + @Test + public void testPackageChanged() throws Exception { + setupPackageInfosForCoreApps(); + SmsApplication.initSmsPackageMonitor(mContext); + verify(mContext).createContextAsUser(eq(UserHandle.ALL), anyInt()); + ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(BroadcastReceiver.class); + verify(mContext).registerReceiver(captor.capture(), isNotNull(), + isNull(), nullable(Handler.class)); + BroadcastReceiver smsPackageMonitor = captor.getValue(); + + Intent packageChangedIntent = new Intent(Intent.ACTION_PACKAGE_CHANGED); + packageChangedIntent.setData( + Uri.fromParts("package", TEST_COMPONENT_NAME.getPackageName(), null)); + smsPackageMonitor.onReceive(mContext, packageChangedIntent); + + ArgumentCaptor<IntentFilter> intentFilterCaptor = + ArgumentCaptor.forClass(IntentFilter.class); + verify(mPackageManager, times(SCHEMES_FOR_PREFERRED_APP.size())) + .replacePreferredActivity(intentFilterCaptor.capture(), + eq(IntentFilter.MATCH_CATEGORY_SCHEME + | IntentFilter.MATCH_ADJUSTMENT_NORMAL), + isNotNull(List.class), + eq(new ComponentName(TEST_COMPONENT_NAME.getPackageName(), SEND_TO_NAME))); + + Set<String> capturedSchemes = intentFilterCaptor.getAllValues().stream() + .map(intentFilter -> intentFilter.getDataScheme(0)) + .collect(Collectors.toSet()); + assertEquals(SCHEMES_FOR_PREFERRED_APP.size(), capturedSchemes.size()); + assertTrue(SCHEMES_FOR_PREFERRED_APP.containsAll(capturedSchemes)); + } + private void setupPackageInfosForCoreApps() throws Exception { PackageInfo phonePackageInfo = new PackageInfo(); ApplicationInfo phoneApplicationInfo = new ApplicationInfo(); 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/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 |