diff options
105 files changed, 2604 insertions, 873 deletions
diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp index 2150cb41ff5b..52a61674a596 100644 --- a/apex/permission/framework/Android.bp +++ b/apex/permission/framework/Android.bp @@ -27,7 +27,10 @@ java_sdk_library { defaults: ["framework-module-defaults"], // Restrict access to implementation library. - impl_library_visibility: ["//frameworks/base/apex/permission:__subpackages__"], + impl_library_visibility: [ + "//frameworks/base/apex/permission:__subpackages__", + "//packages/modules/Permission:__subpackages__", + ], srcs: [ ":framework-permission-sources", diff --git a/apex/permission/service/Android.bp b/apex/permission/service/Android.bp index b7f808214507..d0fc5b9d7c14 100644 --- a/apex/permission/service/Android.bp +++ b/apex/permission/service/Android.bp @@ -78,6 +78,7 @@ java_sdk_library { "//frameworks/base/apex/permission/tests", "//frameworks/base/services/tests/mockingservicestests", "//frameworks/base/services/tests/servicestests", + "//packages/modules/Permission/tests", ], srcs: [ ":service-permission-sources", diff --git a/core/api/current.txt b/core/api/current.txt index e8174c0e3fe6..f49ce1fd48a5 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -12344,6 +12344,8 @@ package android.content.pm { field public static final String FEATURE_GAMEPAD = "android.hardware.gamepad"; field public static final String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors"; field public static final String FEATURE_HOME_SCREEN = "android.software.home_screen"; + field public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE = "android.hardware.identity_credential"; + field public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE_DIRECT_ACCESS = "android.hardware.identity_credential_direct_access"; field public static final String FEATURE_INPUT_METHODS = "android.software.input_methods"; field public static final String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels"; field public static final String FEATURE_IRIS = "android.hardware.biometrics.iris"; @@ -25626,6 +25628,8 @@ package android.net { method public void applyTransportModeTransform(@NonNull java.net.Socket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException; method public void applyTransportModeTransform(@NonNull java.net.DatagramSocket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException; method public void applyTransportModeTransform(@NonNull java.io.FileDescriptor, int, @NonNull android.net.IpSecTransform) throws java.io.IOException; + method @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException; + method @NonNull @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; method public void removeTransportModeTransforms(@NonNull java.net.Socket) throws java.io.IOException; @@ -25635,6 +25639,12 @@ package android.net { field public static final int DIRECTION_OUT = 1; // 0x1 } + public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable { + method @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public void addAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException; + method public void close(); + method @RequiresPermission("android.permission.MANAGE_IPSEC_TUNNELS") public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException; + } + public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException { } @@ -36708,15 +36718,20 @@ package android.security.identity { public abstract class IdentityCredential { method @NonNull public abstract java.security.KeyPair createEphemeralKeyPair(); method @NonNull public abstract byte[] decryptMessageFromReader(@NonNull byte[]) throws android.security.identity.MessageDecryptionException; + method @NonNull public byte[] delete(@NonNull byte[]); method @NonNull public abstract byte[] encryptMessageToReader(@NonNull byte[]); method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getAuthKeysNeedingCertification(); method @NonNull public abstract int[] getAuthenticationDataUsageCount(); method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getCredentialKeyCertificateChain(); method @NonNull public abstract android.security.identity.ResultData getEntries(@Nullable byte[], @NonNull java.util.Map<java.lang.String,java.util.Collection<java.lang.String>>, @Nullable byte[], @Nullable byte[]) throws android.security.identity.EphemeralPublicKeyNotFoundException, android.security.identity.InvalidReaderSignatureException, android.security.identity.InvalidRequestMessageException, android.security.identity.NoAuthenticationKeyAvailableException, android.security.identity.SessionTranscriptMismatchException; + method @NonNull public byte[] proveOwnership(@NonNull byte[]); method public abstract void setAllowUsingExhaustedKeys(boolean); + method public void setAllowUsingExpiredKeys(boolean); method public abstract void setAvailableAuthenticationKeys(int, int); method public abstract void setReaderEphemeralPublicKey(@NonNull java.security.PublicKey) throws java.security.InvalidKeyException; - method public abstract void storeStaticAuthenticationData(@NonNull java.security.cert.X509Certificate, @NonNull byte[]) throws android.security.identity.UnknownAuthenticationKeyException; + method @Deprecated public abstract void storeStaticAuthenticationData(@NonNull java.security.cert.X509Certificate, @NonNull byte[]) throws android.security.identity.UnknownAuthenticationKeyException; + method public void storeStaticAuthenticationData(@NonNull java.security.cert.X509Certificate, @NonNull java.time.Instant, @NonNull byte[]) throws android.security.identity.UnknownAuthenticationKeyException; + method @NonNull public byte[] update(@NonNull android.security.identity.PersonalizationData); } public class IdentityCredentialException extends java.lang.Exception { @@ -36726,7 +36741,7 @@ package android.security.identity { public abstract class IdentityCredentialStore { method @NonNull public abstract android.security.identity.WritableIdentityCredential createCredential(@NonNull String, @NonNull String) throws android.security.identity.AlreadyPersonalizedException, android.security.identity.DocTypeNotSupportedException; - method @Nullable public abstract byte[] deleteCredentialByName(@NonNull String); + method @Deprecated @Nullable public abstract byte[] deleteCredentialByName(@NonNull String); method @Nullable public abstract android.security.identity.IdentityCredential getCredentialByName(@NonNull String, int) throws android.security.identity.CipherSuiteNotSupportedException; method @Nullable public static android.security.identity.IdentityCredentialStore getDirectAccessInstance(@NonNull android.content.Context); method @Nullable public static android.security.identity.IdentityCredentialStore getInstance(@NonNull android.content.Context); @@ -40208,6 +40223,7 @@ package android.telephony { field public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool"; field public static final String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool"; field public static final String KEY_RTT_SUPPORTED_FOR_VT_BOOL = "rtt_supported_for_vt_bool"; + field public static final String KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL = "rtt_supported_while_roaming_bool"; field public static final String KEY_RTT_UPGRADE_SUPPORTED_BOOL = "rtt_upgrade_supported_bool"; field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool"; field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool"; diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index cb2810c08d91..0915d0763604 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -160,6 +160,10 @@ package android.net { method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle); } + public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable { + method public int getResourceId(); + } + public final class NetworkCapabilities implements android.os.Parcelable { field public static final int TRANSPORT_TEST = 7; // 0x7 } diff --git a/core/api/system-current.txt b/core/api/system-current.txt index d34f95633cad..b3e78ab7377a 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -1624,6 +1624,15 @@ package android.app.usage { } +package android.apphibernation { + + public final class AppHibernationManager { + method public boolean isHibernating(@NonNull String); + method public void setHibernating(@NonNull String, boolean); + } + +} + package android.bluetooth { public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile { @@ -1920,6 +1929,7 @@ package android.content { method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle); method public abstract void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle); method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle); + field public static final String APP_HIBERNATION_SERVICE = "app_hibernation"; field public static final String APP_INTEGRITY_SERVICE = "app_integrity"; field public static final String APP_PREDICTION_SERVICE = "app_prediction"; field public static final String BACKUP_SERVICE = "backup"; @@ -6926,15 +6936,11 @@ package android.net { } public final class IpSecManager { - method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException; - method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; + method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; } public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable { - method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException; - method public void close(); method @NonNull public String getInterfaceName(); - method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException; } public static class IpSecTransform.Builder { diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS index 60bfac566879..afa1560420f7 100644 --- a/core/java/android/app/OWNERS +++ b/core/java/android/app/OWNERS @@ -50,6 +50,9 @@ per-file *StatusBar* = file:/packages/SystemUI/OWNERS # ResourcesManager per-file ResourcesManager = rtmitchell@google.com, toddke@google.com +# VoiceInteraction +per-file *VoiceInteract* = file:/core/java/android/service/voice/OWNERS + # Wallpaper per-file *Wallpaper* = file:/core/java/android/service/wallpaper/OWNERS diff --git a/core/java/android/apphibernation/AppHibernationManager.java b/core/java/android/apphibernation/AppHibernationManager.java new file mode 100644 index 000000000000..8f1934c7b77a --- /dev/null +++ b/core/java/android/apphibernation/AppHibernationManager.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2021 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.apphibernation; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.annotation.SystemService; +import android.content.Context; +import android.os.RemoteException; +import android.os.ServiceManager; + +/** + * This class provides an API surface for system apps to manipulate the app hibernation + * state of a package for the user provided in the context. + * @hide + */ +@SystemApi +@SystemService(Context.APP_HIBERNATION_SERVICE) +public final class AppHibernationManager { + private static final String TAG = "AppHibernationManager"; + private final Context mContext; + private final IAppHibernationService mIAppHibernationService; + + /** + * Creates a new instance. + * + * @param context The current context associated with the user + * + * @hide + */ + public AppHibernationManager(@NonNull Context context) { + mContext = context; + mIAppHibernationService = IAppHibernationService.Stub.asInterface( + ServiceManager.getService(Context.APP_HIBERNATION_SERVICE)); + } + + /** + * Returns true if the package is hibernating, false otherwise. + * + * @hide + */ + @SystemApi + public boolean isHibernating(@NonNull String packageName) { + try { + return mIAppHibernationService.isHibernating(packageName, mContext.getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Set whether the package is hibernating. + * + * @hide + */ + @SystemApi + public void setHibernating(@NonNull String packageName, boolean isHibernating) { + try { + mIAppHibernationService.setHibernating(packageName, mContext.getUserId(), + isHibernating); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } +} diff --git a/core/java/android/apphibernation/IAppHibernationService.aidl b/core/java/android/apphibernation/IAppHibernationService.aidl new file mode 100644 index 000000000000..db57ecb73051 --- /dev/null +++ b/core/java/android/apphibernation/IAppHibernationService.aidl @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2021 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.apphibernation; + +/** + * Binder interface to communicate with AppHibernationService. + * @hide + */ +interface IAppHibernationService { + boolean isHibernating(String packageName, int userId); + void setHibernating(String packageName, int userId, boolean isHibernating); +}
\ No newline at end of file diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index fcb0f4f6f7ab..c5206d77ea50 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4668,6 +4668,17 @@ public abstract class Context { public static final String PERMISSION_CONTROLLER_SERVICE = "permission_controller"; /** + * Use with {@link #getSystemService(String) to retrieve an + * {@link android.apphibernation.AppHibernationManager}} for + * communicating with the hibernation service. + * @hide + * + * @see #getSystemService(String) + */ + @SystemApi + public static final String APP_HIBERNATION_SERVICE = "app_hibernation"; + + /** * Use with {@link #getSystemService(String)} to retrieve an * {@link android.app.backup.IBackupManager IBackupManager} for communicating * with the backup mechanism. diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 4ffdf67a4e1c..fcd573ea3b65 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2443,6 +2443,35 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device supports + * {@link android.security.identity.IdentityCredentialStore} implemented in secure hardware + * at the given feature version. + * + * <p>Known feature versions include: + * <ul> + * <li><code>202009</code>: corresponds to the features included in the Identity Credential + * API shipped in Android 11. + * <li><code>202101</code>: corresponds to the features included in the Identity Credential + * API shipped in Android 12. + * </ul> + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE = + "android.hardware.identity_credential"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device supports + * {@link android.security.identity.IdentityCredentialStore} implemented in secure hardware + * with direct access at the given feature version. + * See {@link #FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known feature versions. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE_DIRECT_ACCESS = + "android.hardware.identity_credential_direct_access"; + + /** + * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device supports one or more methods of * reporting current location. */ diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl index c3b6c052500a..c093489d4494 100644 --- a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl +++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl @@ -32,6 +32,12 @@ oneway interface IUdfpsOverlayController { // Hides the overlay. void hideUdfpsOverlay(int sensorId); + // Notifies of enrollment progress changes. + void onEnrollmentProgress(int sensorId, int remaining); + + // Notifies when a non-terminal error occurs (e.g. user moved their finger too fast). + void onEnrollmentHelp(int sensorId); + // Shows debug messages on the UDFPS overlay. void setDebugMessage(int sensorId, String message); } diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java index 4ec3f926ed86..b90c72832d36 100644 --- a/core/java/android/hardware/hdmi/HdmiControlManager.java +++ b/core/java/android/hardware/hdmi/HdmiControlManager.java @@ -503,6 +503,29 @@ public final class HdmiControlManager { @Retention(RetentionPolicy.SOURCE) public @interface TvWakeOnOneTouchPlay {} + // -- Whether TV should send <Standby> on sleep. + /** + * Sending <Standby> on sleep. + * + * @hide + */ + public static final int TV_SEND_STANDBY_ON_SLEEP_ENABLED = 1; + /** + * Not sending <Standby> on sleep. + * + * @hide + */ + public static final int TV_SEND_STANDBY_ON_SLEEP_DISABLED = 0; + /** + * @hide + */ + @IntDef(prefix = { "TV_SEND_STANDBY_ON_SLEEP_" }, value = { + TV_SEND_STANDBY_ON_SLEEP_ENABLED, + TV_SEND_STANDBY_ON_SLEEP_DISABLED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface TvSendStandbyOnSleep {} + // -- The RC profile of a TV panel. /** * RC profile none. @@ -747,6 +770,14 @@ public final class HdmiControlManager { public static final String CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY = "tv_wake_on_one_touch_play"; /** + * Name of a setting deciding whether the device will also turn off other CEC devices + * when it goes to standby mode. + * + * @hide + */ + public static final String CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP = + "tv_send_standby_on_sleep"; + /** * Name of a setting representing the RC profile of a TV panel. * * @hide @@ -805,12 +836,13 @@ public final class HdmiControlManager { CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING, CEC_SETTING_NAME_VOLUME_CONTROL_MODE, CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY, + CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, CEC_SETTING_NAME_RC_PROFILE_TV, CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU, CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_SETUP_MENU, CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_CONTENTS_MENU, CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_TOP_MENU, - CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU + CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_MEDIA_CONTEXT_SENSITIVE_MENU, }) public @interface CecSettingName {} @@ -2158,4 +2190,48 @@ public final class HdmiControlManager { throw e.rethrowFromSystemServer(); } } + + /** + * Set the current status of TV send <Standby> on Sleep. + * + * <p>Sets whether the device will also turn off other CEC devices + * when it goes to standby mode. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.HDMI_CEC) + public void setTvSendStandbyOnSleep(@NonNull @TvSendStandbyOnSleep int value) { + if (mService == null) { + Log.e(TAG, "HdmiControlService is not available"); + throw new RuntimeException("HdmiControlService is not available"); + } + try { + mService.setCecSettingIntValue(CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, value); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Get the current status of TV send <Standby> on Sleep. + * + * <p>Reflects whether the device will also turn off other CEC devices + * when it goes to standby mode. + * + * @hide + */ + @NonNull + @TvSendStandbyOnSleep + @RequiresPermission(android.Manifest.permission.HDMI_CEC) + public int getTvSendStandbyOnSleep() { + if (mService == null) { + Log.e(TAG, "HdmiControlService is not available"); + throw new RuntimeException("HdmiControlService is not available"); + } + try { + return mService.getCecSettingIntValue(CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 6fecee632d62..719783163ab9 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -31,6 +31,7 @@ import android.net.NetworkRequest; import android.net.NetworkState; import android.net.ProxyInfo; import android.net.UidRange; +import android.net.VpnInfo; import android.net.QosSocketInfo; import android.os.Bundle; import android.os.IBinder; @@ -43,7 +44,6 @@ import android.os.ResultReceiver; import com.android.connectivity.aidl.INetworkAgent; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; -import com.android.internal.net.VpnInfo; import com.android.internal.net.VpnProfile; /** diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 1a3dc974480c..d5aede71011f 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -23,11 +23,11 @@ import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; +import android.net.VpnInfo; import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.os.IBinder; import android.os.Messenger; -import com.android.internal.net.VpnInfo; /** {@hide} */ interface INetworkStatsService { diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index d83715c692f7..60923f5ea8c6 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -15,6 +15,8 @@ */ package android.net; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; + import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; @@ -628,7 +630,7 @@ public final class IpSecManager { } /** @hide */ - @VisibleForTesting + @SystemApi(client = MODULE_LIBRARIES) public int getResourceId() { return mResourceId; } @@ -705,7 +707,7 @@ public final class IpSecManager { } /** - * This class represents an IpSecTunnelInterface + * This class represents an IpSecTunnelInterface. * * <p>IpSecTunnelInterface objects track tunnel interfaces that serve as * local endpoints for IPsec tunnels. @@ -714,9 +716,7 @@ public final class IpSecManager { * applied to provide IPsec security to packets sent through the tunnel. While a tunnel * cannot be used in standalone mode within Android, the higher layers may use the tunnel * to create Network objects which are accessible to the Android system. - * @hide */ - @SystemApi public static final class IpSecTunnelInterface implements AutoCloseable { private final String mOpPackageName; private final IIpSecService mService; @@ -727,23 +727,26 @@ public final class IpSecManager { private String mInterfaceName; private int mResourceId = INVALID_RESOURCE_ID; - /** Get the underlying SPI held by this object. */ + /** + * Get the underlying SPI held by this object. + * + * @hide + */ + @SystemApi @NonNull public String getInterfaceName() { return mInterfaceName; } /** - * Add an address to the IpSecTunnelInterface + * Add an address to the IpSecTunnelInterface. * * <p>Add an address which may be used as the local inner address for * tunneled traffic. * * @param address the local address for traffic inside the tunnel * @param prefixLen length of the InetAddress prefix - * @hide */ - @SystemApi @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException { @@ -758,15 +761,13 @@ public final class IpSecManager { } /** - * Remove an address from the IpSecTunnelInterface + * Remove an address from the IpSecTunnelInterface. * - * <p>Remove an address which was previously added to the IpSecTunnelInterface + * <p>Remove an address which was previously added to the IpSecTunnelInterface. * * @param address to be removed * @param prefixLen length of the InetAddress prefix - * @hide */ - @SystemApi @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException { @@ -817,7 +818,7 @@ public final class IpSecManager { } /** - * Delete an IpSecTunnelInterface + * Delete an IpSecTunnelInterface. * * <p>Calling close will deallocate the IpSecTunnelInterface and all of its system * resources. Any packets bound for this interface either inbound or outbound will @@ -839,7 +840,12 @@ public final class IpSecManager { } } - /** Check that the Interface was closed properly. */ + + /** + * Check that the Interface was closed properly. + * + * @hide + */ @Override protected void finalize() throws Throwable { if (mCloseGuard != null) { @@ -871,17 +877,52 @@ public final class IpSecManager { * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic. * * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the - * underlying network goes away, and the onLost() callback is received. + * underlying network disconnects, and the {@link + * ConnectivityManager.NetworkCallback#onLost(Network)} callback is received. + * + * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. Packets + * that go through the tunnel will need a underlying network to transit to the IPsec peer. + * This network should almost certainly be a physical network such as WiFi. + * @return a new {@link IpSecTunnelInterface} with the specified properties + * @throws IOException indicating that the tunnel could not be created due to a lower-layer + * error + * @throws ResourceUnavailableException indicating that the number of opening tunnels has + * reached the limit. + */ + @NonNull + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) + public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull Network underlyingNetwork) + throws ResourceUnavailableException, IOException { + + // TODO: Remove the need for adding two unused addresses with IPsec tunnels when {@link + // #createIpSecTunnelInterface(localAddress, remoteAddress, underlyingNetwork)} can be + // safely removed. + final InetAddress address = InetAddress.getLocalHost(); + return createIpSecTunnelInterface(address, address, underlyingNetwork); + } + + /** + * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic. * - * @param localAddress The local addres of the tunnel - * @param remoteAddress The local addres of the tunnel - * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. - * This network should almost certainly be a network such as WiFi with an L2 address. - * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties - * @throws IOException indicating that the socket could not be opened or bound - * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open + * <p>An application that creates tunnels is responsible for cleaning up the tunnel when the + * underlying network disconnects, and the {@link + * ConnectivityManager.NetworkCallback#onLost(Network)} callback is received. + * + * @param localAddress The local address of the tunnel + * @param remoteAddress The local address of the tunnel + * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. Packets + * that go through the tunnel will need a underlying network to transit to the IPsec peer. + * This network should almost certainly be a physical network such as WiFi. + * @return a new {@link IpSecTunnelInterface} with the specified properties + * @throws IOException indicating that the tunnel could not be created due to a lower-layer + * error + * @throws ResourceUnavailableException indicating that the number of opening tunnels has + * reached the limit. * @hide + * @deprecated Callers should use {@link #createIpSecTunnelInterface(Network)} */ + @Deprecated @SystemApi @NonNull @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @@ -905,16 +946,14 @@ public final class IpSecManager { * <p>Applications should probably not use this API directly. * * - * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied + * @param tunnel The {@link IpSecTunnelInterface} that will use the supplied * transform. - * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which + * @param direction the direction, {@link #DIRECTION_OUT} or {@link #DIRECTION_IN} in which * the transform will be used. * @param transform an {@link IpSecTransform} created in tunnel mode - * @throws IOException indicating that the transform could not be applied due to a lower - * layer failure. - * @hide + * @throws IOException indicating that the transform could not be applied due to a lower-layer + * error */ - @SystemApi @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel, diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index 53996a5fc503..e8298218e456 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -421,7 +421,7 @@ public class Network implements Parcelable { throw new SocketException("Only AF_INET/AF_INET6 sockets supported"); } - final int err = NetworkUtils.bindSocketToNetwork(fd.getInt$(), netId); + final int err = NetworkUtils.bindSocketToNetwork(fd, netId); if (err != 0) { // bindSocketToNetwork returns negative errno. throw new ErrnoException("Binding socket to network " + netId, -err) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index e65c27c2f4bb..06d0fc1bf9d5 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -195,13 +195,15 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { subscriberId = state.subscriberId; if (type == TYPE_WIFI) { - if (state.networkId != null) { - networkId = state.networkId; - } else { - final WifiManager wifi = (WifiManager) context.getSystemService( - Context.WIFI_SERVICE); - final WifiInfo info = wifi.getConnectionInfo(); - networkId = info != null ? info.getSSID() : null; + if (state.networkCapabilities.getSsid() != null) { + networkId = state.networkCapabilities.getSsid(); + if (networkId == null) { + // TODO: Figure out if this code path never runs. If so, remove them. + final WifiManager wifi = (WifiManager) context.getSystemService( + Context.WIFI_SERVICE); + final WifiInfo info = wifi.getConnectionInfo(); + networkId = info != null ? info.getSSID() : null; + } } } diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index b5962c5bae14..8be4af7b1396 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -81,11 +81,11 @@ public class NetworkUtils { public native static boolean bindProcessToNetworkForHostResolution(int netId); /** - * Explicitly binds {@code socketfd} to the network designated by {@code netId}. This + * Explicitly binds {@code fd} to the network designated by {@code netId}. This * overrides any binding via {@link #bindProcessToNetwork}. * @return 0 on success or negative errno on failure. */ - public native static int bindSocketToNetwork(int socketfd, int netId); + public static native int bindSocketToNetwork(FileDescriptor fd, int netId); /** * Protect {@code fd} from VPN connections. After protecting, data sent through @@ -93,9 +93,7 @@ public class NetworkUtils { * forwarded through the VPN. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static boolean protectFromVpn(FileDescriptor fd) { - return protectFromVpn(fd.getInt$()); - } + public static native boolean protectFromVpn(FileDescriptor fd); /** * Protect {@code socketfd} from VPN connections. After protecting, data sent through diff --git a/core/java/com/android/internal/net/VpnInfo.aidl b/core/java/android/net/VpnInfo.aidl index 6fc97be4095b..8bcaa81f3992 100644 --- a/core/java/com/android/internal/net/VpnInfo.aidl +++ b/core/java/android/net/VpnInfo.aidl @@ -14,6 +14,6 @@ * limitations under the License. */ -package com.android.internal.net; +package android.net; parcelable VpnInfo; diff --git a/core/java/com/android/internal/net/VpnInfo.java b/core/java/android/net/VpnInfo.java index e74af5eb50de..cf58c570f21f 100644 --- a/core/java/com/android/internal/net/VpnInfo.java +++ b/core/java/android/net/VpnInfo.java @@ -11,11 +11,13 @@ * 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.net; +package android.net; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; @@ -23,14 +25,28 @@ import java.util.Arrays; /** * A lightweight container used to carry information of the ongoing VPN. - * Internal use only.. + * Internal use only. * * @hide */ public class VpnInfo implements Parcelable { - public int ownerUid; - public String vpnIface; - public String[] underlyingIfaces; + public final int ownerUid; + @Nullable + public final String vpnIface; + @Nullable + public final String[] underlyingIfaces; + + public VpnInfo(int ownerUid, @Nullable String vpnIface, @Nullable String[] underlyingIfaces) { + this.ownerUid = ownerUid; + this.vpnIface = vpnIface; + this.underlyingIfaces = underlyingIfaces; + } + + private VpnInfo(@NonNull Parcel in) { + this.ownerUid = in.readInt(); + this.vpnIface = in.readString(); + this.underlyingIfaces = in.createStringArray(); + } @Override public String toString() { @@ -47,22 +63,21 @@ public class VpnInfo implements Parcelable { } @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(ownerUid); dest.writeString(vpnIface); dest.writeStringArray(underlyingIfaces); } + @NonNull public static final Parcelable.Creator<VpnInfo> CREATOR = new Parcelable.Creator<VpnInfo>() { + @NonNull @Override - public VpnInfo createFromParcel(Parcel source) { - VpnInfo info = new VpnInfo(); - info.ownerUid = source.readInt(); - info.vpnIface = source.readString(); - info.underlyingIfaces = source.readStringArray(); - return info; + public VpnInfo createFromParcel(@NonNull Parcel in) { + return new VpnInfo(in); } + @NonNull @Override public VpnInfo[] newArray(int size) { return new VpnInfo[size]; diff --git a/core/java/android/net/vcn/VcnConfig.java b/core/java/android/net/vcn/VcnConfig.java index ede8faaaf261..5eb4ba6a2f8e 100644 --- a/core/java/android/net/vcn/VcnConfig.java +++ b/core/java/android/net/vcn/VcnConfig.java @@ -96,7 +96,11 @@ public final class VcnConfig implements Parcelable { return mPackageName; } - /** Retrieves the set of configured tunnels. */ + /** + * Retrieves the set of configured tunnels. + * + * @hide + */ @NonNull public Set<VcnGatewayConnectionConfig> getGatewayConnectionConfigs() { return Collections.unmodifiableSet(mGatewayConnectionConfigs); @@ -146,7 +150,7 @@ public final class VcnConfig implements Parcelable { } @Override - public void writeToParcel(Parcel out, int flags) { + public void writeToParcel(@NonNull Parcel out, int flags) { out.writeParcelable(toPersistableBundle(), flags); } @@ -164,8 +168,12 @@ public final class VcnConfig implements Parcelable { } }; - /** This class is used to incrementally build {@link VcnConfig} objects. */ - public static class Builder { + /** + * This class is used to incrementally build {@link VcnConfig} objects. + * + * @hide + */ + public static final class Builder { @NonNull private final String mPackageName; @NonNull @@ -182,6 +190,7 @@ public final class VcnConfig implements Parcelable { * * @param gatewayConnectionConfig the configuration for an individual gateway connection * @return this {@link Builder} instance, for chaining + * @hide */ @NonNull public Builder addGatewayConnectionConfig( @@ -196,6 +205,7 @@ public final class VcnConfig implements Parcelable { * Builds and validates the VcnConfig. * * @return an immutable VcnConfig instance + * @hide */ @NonNull public VcnConfig build() { diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java index d531cdb2a6e9..cead2f1caad1 100644 --- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java @@ -17,6 +17,7 @@ package android.net.vcn; import static com.android.internal.annotations.VisibleForTesting.Visibility; +import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; @@ -25,14 +26,19 @@ import android.os.PersistableBundle; import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.Preconditions; import com.android.server.vcn.util.PersistableBundleUtils; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Objects; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.concurrent.TimeUnit; /** @@ -97,6 +103,26 @@ public final class VcnGatewayConnectionConfig { ALLOWED_CAPABILITIES = Collections.unmodifiableSet(allowedCaps); } + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = {"NET_CAPABILITY_"}, + value = { + NetworkCapabilities.NET_CAPABILITY_MMS, + NetworkCapabilities.NET_CAPABILITY_SUPL, + NetworkCapabilities.NET_CAPABILITY_DUN, + NetworkCapabilities.NET_CAPABILITY_FOTA, + NetworkCapabilities.NET_CAPABILITY_IMS, + NetworkCapabilities.NET_CAPABILITY_CBS, + NetworkCapabilities.NET_CAPABILITY_IA, + NetworkCapabilities.NET_CAPABILITY_RCS, + NetworkCapabilities.NET_CAPABILITY_XCAP, + NetworkCapabilities.NET_CAPABILITY_EIMS, + NetworkCapabilities.NET_CAPABILITY_INTERNET, + NetworkCapabilities.NET_CAPABILITY_MCX, + }) + public @interface VcnSupportedCapability {} + private static final int DEFAULT_MAX_MTU = 1500; /** @@ -128,10 +154,10 @@ public final class VcnGatewayConnectionConfig { }; private static final String EXPOSED_CAPABILITIES_KEY = "mExposedCapabilities"; - @NonNull private final Set<Integer> mExposedCapabilities; + @NonNull private final SortedSet<Integer> mExposedCapabilities; private static final String UNDERLYING_CAPABILITIES_KEY = "mUnderlyingCapabilities"; - @NonNull private final Set<Integer> mUnderlyingCapabilities; + @NonNull private final SortedSet<Integer> mUnderlyingCapabilities; // TODO: Add Ike/ChildSessionParams as a subclass - maybe VcnIkeGatewayConnectionConfig @@ -141,14 +167,14 @@ public final class VcnGatewayConnectionConfig { private static final String RETRY_INTERVAL_MS_KEY = "mRetryIntervalsMs"; @NonNull private final long[] mRetryIntervalsMs; - @VisibleForTesting(visibility = Visibility.PRIVATE) - public VcnGatewayConnectionConfig( + /** Builds a VcnGatewayConnectionConfig with the specified parameters. */ + private VcnGatewayConnectionConfig( @NonNull Set<Integer> exposedCapabilities, @NonNull Set<Integer> underlyingCapabilities, @NonNull long[] retryIntervalsMs, @IntRange(from = MIN_MTU_V6) int maxMtu) { - mExposedCapabilities = exposedCapabilities; - mUnderlyingCapabilities = underlyingCapabilities; + mExposedCapabilities = new TreeSet(exposedCapabilities); + mUnderlyingCapabilities = new TreeSet(underlyingCapabilities); mRetryIntervalsMs = retryIntervalsMs; mMaxMtu = maxMtu; @@ -163,9 +189,9 @@ public final class VcnGatewayConnectionConfig { final PersistableBundle underlyingCapsBundle = in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY); - mExposedCapabilities = new ArraySet<>(PersistableBundleUtils.toList( + mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList( exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); - mUnderlyingCapabilities = new ArraySet<>(PersistableBundleUtils.toList( + mUnderlyingCapabilities = new TreeSet<>(PersistableBundleUtils.toList( underlyingCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER)); mRetryIntervalsMs = in.getLongArray(RETRY_INTERVAL_MS_KEY); mMaxMtu = in.getInt(MAX_MTU_KEY); @@ -219,52 +245,93 @@ public final class VcnGatewayConnectionConfig { /** * Returns all exposed capabilities. * + * <p>The returned integer-value capabilities will not contain duplicates, and will be sorted in + * ascending numerical order. + * + * @see Builder#addExposedCapability(int) + * @see Builder#clearExposedCapability(int) * @hide */ @NonNull + public int[] getExposedCapabilities() { + // Sorted set guarantees ordering + return ArrayUtils.convertToIntArray(new ArrayList<>(mExposedCapabilities)); + } + + /** + * Returns all exposed capabilities. + * + * <p>Left to prevent the need to make major changes while changes are actively in flight. + * + * @deprecated use getExposedCapabilities() instead + * @hide + */ + @Deprecated + @NonNull public Set<Integer> getAllExposedCapabilities() { return Collections.unmodifiableSet(mExposedCapabilities); } /** - * Checks if this config is configured to support/expose a specific capability. + * Returns all capabilities required of underlying networks. * - * @param capability the capability to check for + * <p>The returned integer-value capabilities will be sorted in ascending numerical order. + * + * @see Builder#addRequiredUnderlyingCapability(int) + * @see Builder#clearRequiredUnderlyingCapability(int) + * @hide */ - public boolean hasExposedCapability(int capability) { - checkValidCapability(capability); - - return mExposedCapabilities.contains(capability); + @NonNull + public int[] getRequiredUnderlyingCapabilities() { + // Sorted set guarantees ordering + return ArrayUtils.convertToIntArray(new ArrayList<>(mUnderlyingCapabilities)); } /** * Returns all capabilities required of underlying networks. * + * <p>Left to prevent the need to make major changes while changes are actively in flight. + * + * @deprecated use getRequiredUnderlyingCapabilities() instead * @hide */ + @Deprecated @NonNull public Set<Integer> getAllUnderlyingCapabilities() { return Collections.unmodifiableSet(mUnderlyingCapabilities); } /** - * Checks if this config requires an underlying network to have the specified capability. + * Retrieves the configured retry intervals. * - * @param capability the capability to check for + * @see Builder#setRetryInterval(long[]) + * @hide */ - public boolean requiresUnderlyingCapability(int capability) { - checkValidCapability(capability); - - return mUnderlyingCapabilities.contains(capability); + @NonNull + public long[] getRetryInterval() { + return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length); } - /** Retrieves the configured retry intervals. */ + /** + * Retrieves the configured retry intervals. + * + * <p>Left to prevent the need to make major changes while changes are actively in flight. + * + * @deprecated use getRequiredUnderlyingCapabilities() instead + * @hide + */ + @Deprecated @NonNull public long[] getRetryIntervalsMs() { - return Arrays.copyOf(mRetryIntervalsMs, mRetryIntervalsMs.length); + return getRetryInterval(); } - /** Retrieves the maximum MTU allowed for this Gateway Connection. */ + /** + * Retrieves the maximum MTU allowed for this Gateway Connection. + * + * @see Builder.setMaxMtu(int) + * @hide + */ @IntRange(from = MIN_MTU_V6) public int getMaxMtu() { return mMaxMtu; @@ -319,8 +386,12 @@ public final class VcnGatewayConnectionConfig { && mMaxMtu == rhs.mMaxMtu; } - /** This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects. */ - public static class Builder { + /** + * This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects. + * + * @hide + */ + public static final class Builder { @NonNull private final Set<Integer> mExposedCapabilities = new ArraySet(); @NonNull private final Set<Integer> mUnderlyingCapabilities = new ArraySet(); @NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS; @@ -338,8 +409,10 @@ public final class VcnGatewayConnectionConfig { * @return this {@link Builder} instance, for chaining * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway * Connection + * @hide */ - public Builder addExposedCapability(int exposedCapability) { + @NonNull + public Builder addExposedCapability(@VcnSupportedCapability int exposedCapability) { checkValidCapability(exposedCapability); mExposedCapabilities.add(exposedCapability); @@ -354,8 +427,10 @@ public final class VcnGatewayConnectionConfig { * @return this {@link Builder} instance, for chaining * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway * Connection + * @hide */ - public Builder removeExposedCapability(int exposedCapability) { + @NonNull + public Builder clearExposedCapability(@VcnSupportedCapability int exposedCapability) { checkValidCapability(exposedCapability); mExposedCapabilities.remove(exposedCapability); @@ -370,8 +445,11 @@ public final class VcnGatewayConnectionConfig { * @return this {@link Builder} instance, for chaining * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying * networks + * @hide */ - public Builder addRequiredUnderlyingCapability(int underlyingCapability) { + @NonNull + public Builder addRequiredUnderlyingCapability( + @VcnSupportedCapability int underlyingCapability) { checkValidCapability(underlyingCapability); mUnderlyingCapabilities.add(underlyingCapability); @@ -390,8 +468,11 @@ public final class VcnGatewayConnectionConfig { * @return this {@link Builder} instance, for chaining * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying * networks + * @hide */ - public Builder removeRequiredUnderlyingCapability(int underlyingCapability) { + @NonNull + public Builder clearRequiredUnderlyingCapability( + @VcnSupportedCapability int underlyingCapability) { checkValidCapability(underlyingCapability); mUnderlyingCapabilities.remove(underlyingCapability); @@ -420,6 +501,7 @@ public final class VcnGatewayConnectionConfig { * 15m]} * @return this {@link Builder} instance, for chaining * @see VcnManager for additional discussion on fail-safe mode + * @hide */ @NonNull public Builder setRetryInterval(@NonNull long[] retryIntervalsMs) { @@ -441,6 +523,7 @@ public final class VcnGatewayConnectionConfig { * @param maxMtu the maximum MTU allowed for this Gateway Connection. Must be greater than * the IPv6 minimum MTU of 1280. Defaults to 1500. * @return this {@link Builder} instance, for chaining + * @hide */ @NonNull public Builder setMaxMtu(@IntRange(from = MIN_MTU_V6) int maxMtu) { @@ -455,6 +538,7 @@ public final class VcnGatewayConnectionConfig { * Builds and validates the VcnGatewayConnectionConfig. * * @return an immutable VcnGatewayConnectionConfig instance + * @hide */ @NonNull public VcnGatewayConnectionConfig build() { diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java index 2ccdc2633af0..2d0a6d74cb86 100644 --- a/core/java/android/net/vcn/VcnManager.java +++ b/core/java/android/net/vcn/VcnManager.java @@ -65,6 +65,7 @@ import java.util.concurrent.Executor; public final class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); + /** @hide */ @VisibleForTesting public static final Map< VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder> diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS index 7e17a082840b..ff126e12cf61 100644 --- a/core/java/android/os/storage/OWNERS +++ b/core/java/android/os/storage/OWNERS @@ -1,10 +1,10 @@ # Bug component: 95221 -narayan@google.com -nandana@google.com corinac@google.com +nandana@google.com zezeozue@google.com maco@google.com sahanas@google.com abkaur@google.com chiangi@google.com +narayan@google.com diff --git a/core/java/android/util/OWNERS b/core/java/android/util/OWNERS index 8f3d9f6f5881..14aa38682d2b 100644 --- a/core/java/android/util/OWNERS +++ b/core/java/android/util/OWNERS @@ -1,3 +1,6 @@ per-file FeatureFlagUtils.java = sbasi@google.com per-file FeatureFlagUtils.java = tmfang@google.com per-file FeatureFlagUtils.java = asapperstein@google.com + +per-file TypedValue.java = file:/core/java/android/content/res/OWNERS +per-file AttributeSet.java = file:/core/java/android/content/res/OWNERS diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 2155246cd544..e2af87ee1adf 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -18,6 +18,7 @@ #include <vector> +#include <android/file_descriptor_jni.h> #include <arpa/inet.h> #include <linux/filter.h> #include <linux/if_arp.h> @@ -83,7 +84,7 @@ static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jobject clazz, filter_code, }; - int fd = jniGetFDFromFileDescriptor(env, javaFd); + int fd = AFileDescriptor_getFD(env, javaFd); if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) { jniThrowExceptionFmt(env, "java/net/SocketException", "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno)); @@ -93,7 +94,7 @@ static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jobject clazz, static void android_net_utils_detachBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd) { int optval_ignored = 0; - int fd = jniGetFDFromFileDescriptor(env, javaFd); + int fd = AFileDescriptor_getFD(env, javaFd); if (setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, &optval_ignored, sizeof(optval_ignored)) != 0) { jniThrowExceptionFmt(env, "java/net/SocketException", @@ -117,10 +118,9 @@ static jboolean android_net_utils_bindProcessToNetworkForHostResolution(JNIEnv * return (jboolean) !setNetworkForResolv(netId); } -static jint android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, jint socket, - jint netId) -{ - return setNetworkForSocket(netId, socket); +static jint android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, jobject javaFd, + jint netId) { + return setNetworkForSocket(netId, AFileDescriptor_getFD(env, javaFd)); } static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint socket) @@ -128,6 +128,10 @@ static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint return (jboolean) !protectFromVpn(socket); } +static jboolean android_net_utils_protectFromVpnWithFd(JNIEnv *env, jobject thiz, jobject javaFd) { + return android_net_utils_protectFromVpn(env, thiz, AFileDescriptor_getFD(env, javaFd)); +} + static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jint uid, jint netId) { return (jboolean) !queryUserAccess(uid, netId); @@ -178,7 +182,7 @@ static jobject android_net_utils_resNetworkSend(JNIEnv *env, jobject thiz, jint } static jobject android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) { - int fd = jniGetFDFromFileDescriptor(env, javaFd); + int fd = AFileDescriptor_getFD(env, javaFd); int rcode; std::vector<uint8_t> buf(MAXPACKETSIZE, 0); @@ -205,7 +209,7 @@ static jobject android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, job } static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) { - int fd = jniGetFDFromFileDescriptor(env, javaFd); + int fd = AFileDescriptor_getFD(env, javaFd); resNetworkCancel(fd); jniSetFileDescriptorOfFD(env, javaFd, -1); } @@ -231,7 +235,7 @@ static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, j return NULL; } - int fd = jniGetFDFromFileDescriptor(env, javaFd); + int fd = AFileDescriptor_getFD(env, javaFd); struct tcp_repair_window trw = {}; socklen_t size = sizeof(trw); @@ -271,8 +275,9 @@ static const JNINativeMethod gNetworkUtilMethods[] = { { "bindProcessToNetwork", "(I)Z", (void*) android_net_utils_bindProcessToNetwork }, { "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess }, { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution }, - { "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork }, - { "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn }, + { "bindSocketToNetwork", "(Ljava/io/FileDescriptor;I)I", (void*) android_net_utils_bindSocketToNetwork }, + { "protectFromVpn", "(I)Z", (void*) android_net_utils_protectFromVpn }, + { "protectFromVpn", "(Ljava/io/FileDescriptor;)Z", (void*) android_net_utils_protectFromVpnWithFd }, { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess }, { "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter }, { "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter }, diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 610e0e0b4b89..c359a7da8137 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -68,7 +68,7 @@ message RootWindowContainerProto { // Whether or not the home activity is the recents activity. This is needed for the CTS tests to // know what activity types to check for when invoking splitscreen multi-window. optional bool is_home_recents_component = 6; - repeated IdentifierProto pending_activities = 7; + repeated IdentifierProto pending_activities = 7 [deprecated=true]; } message BarControllerProto { diff --git a/core/sysprop/WatchdogProperties.sysprop b/core/sysprop/WatchdogProperties.sysprop index 1bcc773a9a5d..93e8b788aed9 100644 --- a/core/sysprop/WatchdogProperties.sysprop +++ b/core/sysprop/WatchdogProperties.sysprop @@ -16,7 +16,7 @@ module: "android.sysprop.WatchdogProperties" owner: Platform # To escape the watchdog timeout loop, fatal reboot the system when -# watchdog timed out 'fatal_count' times in 'fatal_window_second' +# watchdog timed out 'fatal_count' times in 'fatal_window_seconds' # seconds, if both values are not 0. Default value of both is 0. prop { api_name: "fatal_count" @@ -26,8 +26,9 @@ prop { access: Readonly } +# See 'fatal_count' for documentation. prop { - api_name: "fatal_window_second" + api_name: "fatal_window_seconds" type: Integer prop_name: "framework_watchdog.fatal_window.second" scope: Internal @@ -35,9 +36,9 @@ prop { } # The fatal counting can be disabled by setting property -# 'is_fatal_ignore' to true. +# 'should_ignore_fatal_count' to true. prop { - api_name: "is_fatal_ignore" + api_name: "should_ignore_fatal_count" type: Boolean prop_name: "persist.debug.framework_watchdog.fatal_ignore" scope: Internal diff --git a/core/sysprop/api/com.android.sysprop.watchdog-latest.txt b/core/sysprop/api/com.android.sysprop.watchdog-latest.txt index d901aef945c9..c8462111fa94 100644 --- a/core/sysprop/api/com.android.sysprop.watchdog-latest.txt +++ b/core/sysprop/api/com.android.sysprop.watchdog-latest.txt @@ -7,13 +7,13 @@ props { prop_name: "framework_watchdog.fatal_count" } prop { - api_name: "fatal_window_second" + api_name: "fatal_window_seconds" type: Integer scope: Internal prop_name: "framework_watchdog.fatal_window.second" } prop { - api_name: "is_fatal_ignore" + api_name: "should_ignore_fatal_count" scope: Internal prop_name: "persist.debug.framework_watchdog.fatal_ignore" } diff --git a/core/tests/coretests/src/android/app/OWNERS b/core/tests/coretests/src/android/app/OWNERS index bd7da0c3f209..b3f399363aef 100644 --- a/core/tests/coretests/src/android/app/OWNERS +++ b/core/tests/coretests/src/android/app/OWNERS @@ -1 +1,6 @@ per-file Window*.java = file:/services/core/java/com/android/server/wm/OWNERS + +# Notification, DND, Status bar +per-file *Notification* = file:/packages/SystemUI/OWNERS +per-file *Zen* = file:/packages/SystemUI/OWNERS +per-file *StatusBar* = file:/packages/SystemUI/OWNERS diff --git a/core/tests/coretests/src/android/app/people/OWNERS b/core/tests/coretests/src/android/app/people/OWNERS new file mode 100644 index 000000000000..6ec8e6aa8d81 --- /dev/null +++ b/core/tests/coretests/src/android/app/people/OWNERS @@ -0,0 +1 @@ +file:/core/java/android/app/people/OWNERS
\ No newline at end of file diff --git a/core/tests/coretests/src/android/content/pm/OWNERS b/core/tests/coretests/src/android/content/pm/OWNERS index 711f5f012b8b..7b7670696bfa 100644 --- a/core/tests/coretests/src/android/content/pm/OWNERS +++ b/core/tests/coretests/src/android/content/pm/OWNERS @@ -1,2 +1,3 @@ per-file AppSearchPersonTest.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS - +per-file SigningDetailsTest.java = mpgroover@google.com +per-file SigningDetailsTest.java = cbrubaker@google.com diff --git a/identity/java/android/security/identity/CredstoreIdentityCredential.java b/identity/java/android/security/identity/CredstoreIdentityCredential.java index 7c0af6def696..6398cee74cba 100644 --- a/identity/java/android/security/identity/CredstoreIdentityCredential.java +++ b/identity/java/android/security/identity/CredstoreIdentityCredential.java @@ -37,6 +37,7 @@ import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.time.Instant; import java.util.Collection; import java.util.LinkedList; import java.util.Map; @@ -237,12 +238,18 @@ class CredstoreIdentityCredential extends IdentityCredential { } private boolean mAllowUsingExhaustedKeys = true; + private boolean mAllowUsingExpiredKeys = false; @Override public void setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys) { mAllowUsingExhaustedKeys = allowUsingExhaustedKeys; } + @Override + public void setAllowUsingExpiredKeys(boolean allowUsingExpiredKeys) { + mAllowUsingExpiredKeys = allowUsingExpiredKeys; + } + private boolean mOperationHandleSet = false; private long mOperationHandle = 0; @@ -256,7 +263,8 @@ class CredstoreIdentityCredential extends IdentityCredential { public long getCredstoreOperationHandle() { if (!mOperationHandleSet) { try { - mOperationHandle = mBinder.selectAuthKey(mAllowUsingExhaustedKeys); + mOperationHandle = mBinder.selectAuthKey(mAllowUsingExhaustedKeys, + mAllowUsingExpiredKeys); mOperationHandleSet = true; } catch (android.os.RemoteException e) { throw new RuntimeException("Unexpected RemoteException ", e); @@ -306,7 +314,8 @@ class CredstoreIdentityCredential extends IdentityCredential { rnsParcels, sessionTranscript != null ? sessionTranscript : new byte[0], readerSignature != null ? readerSignature : new byte[0], - mAllowUsingExhaustedKeys); + mAllowUsingExhaustedKeys, + mAllowUsingExpiredKeys); } catch (android.os.RemoteException e) { throw new RuntimeException("Unexpected RemoteException ", e); } catch (android.os.ServiceSpecificException e) { @@ -410,6 +419,34 @@ class CredstoreIdentityCredential extends IdentityCredential { } @Override + public void storeStaticAuthenticationData(X509Certificate authenticationKey, + Instant expirationDate, + byte[] staticAuthData) + throws UnknownAuthenticationKeyException { + try { + AuthKeyParcel authKeyParcel = new AuthKeyParcel(); + authKeyParcel.x509cert = authenticationKey.getEncoded(); + long millisSinceEpoch = (expirationDate.getEpochSecond() * 1000) + + (expirationDate.getNano() / 1000000); + mBinder.storeStaticAuthenticationDataWithExpiration(authKeyParcel, + millisSinceEpoch, staticAuthData); + } catch (CertificateEncodingException e) { + throw new RuntimeException("Error encoding authenticationKey", e); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + if (e.errorCode == ICredentialStore.ERROR_NOT_SUPPORTED) { + throw new UnsupportedOperationException("Not supported", e); + } else if (e.errorCode == ICredentialStore.ERROR_AUTHENTICATION_KEY_NOT_FOUND) { + throw new UnknownAuthenticationKeyException(e.getMessage(), e); + } else { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + } + + @Override public @NonNull int[] getAuthenticationDataUsageCount() { try { int[] usageCount = mBinder.getAuthenticationDataUsageCount(); @@ -421,4 +458,49 @@ class CredstoreIdentityCredential extends IdentityCredential { + e.errorCode, e); } } + + @Override + public @NonNull byte[] proveOwnership(@NonNull byte[] challenge) { + try { + byte[] proofOfOwnership = mBinder.proveOwnership(challenge); + return proofOfOwnership; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + if (e.errorCode == ICredentialStore.ERROR_NOT_SUPPORTED) { + throw new UnsupportedOperationException("Not supported", e); + } else { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + } + + @Override + public @NonNull byte[] delete(@NonNull byte[] challenge) { + try { + byte[] proofOfDeletion = mBinder.deleteWithChallenge(challenge); + return proofOfDeletion; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + + @Override + public @NonNull byte[] update(@NonNull PersonalizationData personalizationData) { + try { + IWritableCredential binder = mBinder.update(); + byte[] proofOfProvision = + CredstoreWritableIdentityCredential.personalize(binder, personalizationData); + return proofOfProvision; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } } diff --git a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java index 129063361b35..d8d47424e2e8 100644 --- a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java +++ b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java @@ -162,5 +162,4 @@ class CredstoreIdentityCredentialStore extends IdentityCredentialStore { + e.errorCode, e); } } - } diff --git a/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java index 725e3d8e429a..d2e7984ce19f 100644 --- a/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java +++ b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java @@ -76,7 +76,14 @@ class CredstoreWritableIdentityCredential extends WritableIdentityCredential { @NonNull @Override public byte[] personalize(@NonNull PersonalizationData personalizationData) { + return personalize(mBinder, personalizationData); + } + // Used by both personalize() and CredstoreIdentityCredential.update(). + // + @NonNull + static byte[] personalize(IWritableCredential binder, + @NonNull PersonalizationData personalizationData) { Collection<AccessControlProfile> accessControlProfiles = personalizationData.getAccessControlProfiles(); @@ -144,7 +151,7 @@ class CredstoreWritableIdentityCredential extends WritableIdentityCredential { secureUserId = getRootSid(); } try { - byte[] personalizationReceipt = mBinder.personalize(acpParcels, ensParcels, + byte[] personalizationReceipt = binder.personalize(acpParcels, ensParcels, secureUserId); return personalizationReceipt; } catch (android.os.RemoteException e) { @@ -164,5 +171,4 @@ class CredstoreWritableIdentityCredential extends WritableIdentityCredential { return rootSid; } - } diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java index 4eb6e420c07f..8f175bb63edb 100644 --- a/identity/java/android/security/identity/IdentityCredential.java +++ b/identity/java/android/security/identity/IdentityCredential.java @@ -23,6 +23,7 @@ import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.PublicKey; import java.security.cert.X509Certificate; +import java.time.Instant; import java.util.Collection; import java.util.Map; @@ -114,6 +115,25 @@ public abstract class IdentityCredential { public abstract void setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys); /** + * Sets whether to allow using an authentication key which has been expired if no + * other key is available. This must be called prior to calling + * {@link #getEntries(byte[], Map, byte[], byte[])}. + * + * <p>By default this is set to false. + * + * <p>This is only implemented in feature version 202101 or later. If not implemented, the call + * fails with {@link UnsupportedOperationException}. See + * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known + * feature versions. + * + * @param allowUsingExpiredKeys whether to allow using an authentication key which use count + * has been exceeded if no other key is available. + */ + public void setAllowUsingExpiredKeys(boolean allowUsingExpiredKeys) { + throw new UnsupportedOperationException(); + } + + /** * Called by android.hardware.biometrics.CryptoObject#getOpId() to get an * operation handle. * @@ -289,6 +309,21 @@ public abstract class IdentityCredential { * * <p>Each X.509 certificate is signed by CredentialKey. The certificate chain for CredentialKey * can be obtained using the {@link #getCredentialKeyCertificateChain()} method. + + * <p>If the implementation is feature version 202101 or later, + * each X.509 certificate contains an X.509 extension at OID 1.3.6.1.4.1.11129.2.1.26 which + * contains a DER encoded OCTET STRING with the bytes of the CBOR with the following CDDL: + * <pre> + * ProofOfBinding = [ + * "ProofOfBinding", + * bstr, // Contains SHA-256(ProofOfProvisioning) + * ] + * </pre> + * <p>This CBOR enables an issuer to determine the exact state of the credential it + * returns issuer-signed data for. + * + * <p> See {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for + * known feature versions. * * @return A collection of X.509 certificates for dynamic authentication keys that need issuer * certification. @@ -308,16 +343,136 @@ public abstract class IdentityCredential { * the authenticity * and integrity of the credential data fields. * @throws UnknownAuthenticationKeyException If the given authentication key is not recognized. + * @deprecated Use {@link #storeStaticAuthenticationData(X509Certificate, Instant, byte[])} + * instead. */ + @Deprecated public abstract void storeStaticAuthenticationData( @NonNull X509Certificate authenticationKey, @NonNull byte[] staticAuthData) throws UnknownAuthenticationKeyException; /** + * Store authentication data associated with a dynamic authentication key. + * + * This should only be called for an authenticated key returned by + * {@link #getAuthKeysNeedingCertification()}. + * + * <p>This is only implemented in feature version 202101 or later. If not implemented, the call + * fails with {@link UnsupportedOperationException}. See + * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known + * feature versions. + * + * @param authenticationKey The dynamic authentication key for which certification and + * associated static + * authentication data is being provided. + * @param expirationDate The expiration date of the static authentication data. + * @param staticAuthData Static authentication data provided by the issuer that validates + * the authenticity + * and integrity of the credential data fields. + * @throws UnknownAuthenticationKeyException If the given authentication key is not recognized. + */ + public void storeStaticAuthenticationData( + @NonNull X509Certificate authenticationKey, + @NonNull Instant expirationDate, + @NonNull byte[] staticAuthData) + throws UnknownAuthenticationKeyException { + throw new UnsupportedOperationException(); + } + + /** * Get the number of times the dynamic authentication keys have been used. * * @return int array of dynamic authentication key usage counts. */ public @NonNull abstract int[] getAuthenticationDataUsageCount(); + + /** + * Proves ownership of a credential. + * + * <p>This method returns a COSE_Sign1 data structure signed by the CredentialKey + * with payload set to {@code ProofOfDeletion} as defined below.</p> + * + * <p>The returned CBOR is the following:</p> + * <pre> + * ProofOfOwnership = [ + * "ProofOfOwnership", ; tstr + * tstr, ; DocType + * bstr, ; Challenge + * bool ; true if this is a test credential, should + * ; always be false. + * ] + * </pre> + * + * <p>This is only implemented in feature version 202101 or later. If not implemented, the call + * fails with {@link UnsupportedOperationException}. See + * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known + * feature versions. + * + * @param challenge is a non-empty byte array whose contents should be unique, fresh and + * provided by the issuing authority. The value provided is embedded in the + * generated CBOR and enables the issuing authority to verify that the + * returned proof is fresh. + * @return the COSE_Sign1 data structure above + */ + public @NonNull byte[] proveOwnership(@NonNull byte[] challenge) { + throw new UnsupportedOperationException(); + } + + /** + * Deletes a credential. + * + * <p>This method returns a COSE_Sign1 data structure signed by the CredentialKey + * with payload set to {@code ProofOfDeletion} as defined below.</p> + * + * <pre> + * ProofOfDeletion = [ + * "ProofOfDeletion", ; tstr + * tstr, ; DocType + * bstr, ; Challenge + * bool ; true if this is a test credential, should + * ; always be false. + * ] + * </pre> + * + * <p>This is only implemented in feature version 202101 or later. If not implemented, the call + * fails with {@link UnsupportedOperationException}. See + * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known + * feature versions. + * + * @param challenge is a non-empty byte array whose contents should be unique, fresh and + * provided by the issuing authority. The value provided is embedded in the + * generated CBOR and enables the issuing authority to verify that the + * returned proof is fresh. + * @return the COSE_Sign1 data structure above + */ + public @NonNull byte[] delete(@NonNull byte[] challenge) { + throw new UnsupportedOperationException(); + } + + /** + * Updates the credential with new access control profiles and data items. + * + * <p>This method is similar to + * {@link WritableIdentityCredential#personalize(PersonalizationData)} except that it operates + * on an existing credential, see the documentation for that method for the format of the + * returned data. + * + * <p>If this call succeeds an side-effect is that all dynamic authentication keys for the + * credential are deleted. The application will need to use + * {@link #getAuthKeysNeedingCertification()} to generate replacement keys and return + * them for issuer certification. + * + * <p>This is only implemented in feature version 202101 or later. If not implemented, the call + * fails with {@link UnsupportedOperationException}. See + * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known + * feature versions. + * + * @param personalizationData The data to update, including access control profiles + * and data elements and their values, grouped into namespaces. + * @return A COSE_Sign1 data structure, see above. + */ + public @NonNull byte[] update(@NonNull PersonalizationData personalizationData) { + throw new UnsupportedOperationException(); + } } diff --git a/identity/java/android/security/identity/IdentityCredentialStore.java b/identity/java/android/security/identity/IdentityCredentialStore.java index 3843d9279900..6ccd0e892141 100644 --- a/identity/java/android/security/identity/IdentityCredentialStore.java +++ b/identity/java/android/security/identity/IdentityCredentialStore.java @@ -72,6 +72,17 @@ import java.lang.annotation.RetentionPolicy; * <p>Credentials provisioned to the direct access store should <strong>always</strong> use reader * authentication to protect data elements. The reason for this is user authentication or user * approval of data release is not possible when the device is off. + * + * <p>The Identity Credential API is designed to be able to evolve and change over time + * but still provide 100% backwards compatibility. This is complicated by the fact that + * there may be a version skew between the API used by the application and the version + * implemented in secure hardware. To solve this problem, the API provides for a way + * for the application to query which feature version the hardware implements (if any + * at all) using + * {@link android.content.pm#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} and + * {@link android.content.pm#FEATURE_IDENTITY_CREDENTIAL_HARDWARE_DIRECT_ACCESS}. + * Methods which only work on certain feature versions are clearly documented as + * such. */ public abstract class IdentityCredentialStore { IdentityCredentialStore() {} @@ -193,7 +204,9 @@ public abstract class IdentityCredentialStore { * @param credentialName the name of the credential to delete. * @return {@code null} if the credential was not found, the COSE_Sign1 data structure above * if the credential was found and deleted. + * @deprecated Use {@link IdentityCredential#delete(byte[])} instead. */ + @Deprecated public abstract @Nullable byte[] deleteCredentialByName(@NonNull String credentialName); /** @hide */ @@ -201,5 +214,4 @@ public abstract class IdentityCredentialStore { @Retention(RetentionPolicy.SOURCE) public @interface Ciphersuite { } - } diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java index fcc518c374e3..21d23b1b2575 100644 --- a/keystore/java/android/security/Authorization.java +++ b/keystore/java/android/security/Authorization.java @@ -82,7 +82,7 @@ public class Authorization { * * @param locked - whether it is a lock (true) or unlock (false) event * @param syntheticPassword - if it is an unlock event with the password, pass the synthetic - * password provided by the LockSettingService + * password provided by the LockSettingService * * @return 0 if successful or a {@code ResponseCode}. */ diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java index 6ddaa704afa8..b631999c2c54 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java @@ -38,9 +38,10 @@ public class AndroidKeyStoreECPublicKey extends AndroidKeyStorePublicKey impleme public AndroidKeyStoreECPublicKey(@NonNull KeyDescriptor descriptor, @NonNull KeyMetadata metadata, + @NonNull byte[] x509EncodedForm, @NonNull KeyStoreSecurityLevel securityLevel, @NonNull ECParameterSpec params, @NonNull ECPoint w) { - super(descriptor, metadata, KeyProperties.KEY_ALGORITHM_EC, securityLevel); + super(descriptor, metadata, x509EncodedForm, KeyProperties.KEY_ALGORITHM_EC, securityLevel); mParams = params; mW = w; } @@ -48,7 +49,7 @@ public class AndroidKeyStoreECPublicKey extends AndroidKeyStorePublicKey impleme public AndroidKeyStoreECPublicKey(@NonNull KeyDescriptor descriptor, @NonNull KeyMetadata metadata, @NonNull KeyStoreSecurityLevel securityLevel, @NonNull ECPublicKey info) { - this(descriptor, metadata, securityLevel, info.getParams(), info.getW()); + this(descriptor, metadata, info.getEncoded(), securityLevel, info.getParams(), info.getW()); if (!"X.509".equalsIgnoreCase(info.getFormat())) { throw new IllegalArgumentException( "Unsupported key export format: " + info.getFormat()); diff --git a/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java index 49dd77e3a3db..db3e567cb6b4 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStorePublicKey.java @@ -32,13 +32,15 @@ import java.security.PublicKey; public abstract class AndroidKeyStorePublicKey extends AndroidKeyStoreKey implements PublicKey { private final byte[] mCertificate; private final byte[] mCertificateChain; + private final byte[] mEncoded; public AndroidKeyStorePublicKey(@NonNull KeyDescriptor descriptor, - @NonNull KeyMetadata metadata, @NonNull String algorithm, - @NonNull KeyStoreSecurityLevel securityLevel) { + @NonNull KeyMetadata metadata, @NonNull byte[] x509EncodedForm, + @NonNull String algorithm, @NonNull KeyStoreSecurityLevel securityLevel) { super(descriptor, metadata.key.nspace, metadata.authorizations, algorithm, securityLevel); mCertificate = metadata.certificate; mCertificateChain = metadata.certificateChain; + mEncoded = x509EncodedForm; } abstract AndroidKeyStorePrivateKey getPrivateKey(); @@ -50,7 +52,7 @@ public abstract class AndroidKeyStorePublicKey extends AndroidKeyStoreKey implem @Override public byte[] getEncoded() { - return ArrayUtils.cloneIfNotEmpty(mCertificate); + return ArrayUtils.cloneIfNotEmpty(mEncoded); } @Override diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSAPublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSAPublicKey.java index b578ea9baa06..9fe6cf3c113f 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSAPublicKey.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSAPublicKey.java @@ -36,9 +36,11 @@ public class AndroidKeyStoreRSAPublicKey extends AndroidKeyStorePublicKey implem public AndroidKeyStoreRSAPublicKey(@NonNull KeyDescriptor descriptor, @NonNull KeyMetadata metadata, + @NonNull byte[] x509EncodedForm, @NonNull KeyStoreSecurityLevel securityLevel, @NonNull BigInteger modulus, @NonNull BigInteger publicExponent) { - super(descriptor, metadata, KeyProperties.KEY_ALGORITHM_RSA, securityLevel); + super(descriptor, metadata, x509EncodedForm, KeyProperties.KEY_ALGORITHM_RSA, + securityLevel); mModulus = modulus; mPublicExponent = publicExponent; } @@ -46,7 +48,8 @@ public class AndroidKeyStoreRSAPublicKey extends AndroidKeyStorePublicKey implem public AndroidKeyStoreRSAPublicKey(@NonNull KeyDescriptor descriptor, @NonNull KeyMetadata metadata, @NonNull KeyStoreSecurityLevel securityLevel, @NonNull RSAPublicKey info) { - this(descriptor, metadata, securityLevel, info.getModulus(), info.getPublicExponent()); + this(descriptor, metadata, info.getEncoded(), securityLevel, info.getModulus(), + info.getPublicExponent()); if (!"X.509".equalsIgnoreCase(info.getFormat())) { throw new IllegalArgumentException( "Unsupported key export format: " + info.getFormat()); diff --git a/packages/Connectivity/framework/Android.bp b/packages/Connectivity/framework/Android.bp new file mode 100644 index 000000000000..8db8d7699a1e --- /dev/null +++ b/packages/Connectivity/framework/Android.bp @@ -0,0 +1,29 @@ +// +// 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. +// + +// TODO: use a java_library in the bootclasspath instead +filegroup { + name: "framework-connectivity-sources", + srcs: [ + "src/**/*.java", + "src/**/*.aidl", + ], + path: "src", + visibility: [ + "//frameworks/base", + "//packages/modules/Connectivity:__subpackages__", + ], +}
\ No newline at end of file diff --git a/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl b/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl new file mode 100644 index 000000000000..64b556720cd2 --- /dev/null +++ b/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl @@ -0,0 +1,49 @@ +/** + * 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 perNmissions and + * limitations under the License. + */ +package com.android.connectivity.aidl; + +import android.net.NattKeepalivePacketData; +import android.net.QosFilterParcelable; +import android.net.TcpKeepalivePacketData; + +import com.android.connectivity.aidl.INetworkAgentRegistry; + +/** + * Interface to notify NetworkAgent of connectivity events. + * @hide + */ +oneway interface INetworkAgent { + void onRegistered(in INetworkAgentRegistry registry); + void onDisconnected(); + void onBandwidthUpdateRequested(); + void onValidationStatusChanged(int validationStatus, + in @nullable String captivePortalUrl); + void onSaveAcceptUnvalidated(boolean acceptUnvalidated); + void onStartNattSocketKeepalive(int slot, int intervalDurationMs, + in NattKeepalivePacketData packetData); + void onStartTcpSocketKeepalive(int slot, int intervalDurationMs, + in TcpKeepalivePacketData packetData); + void onStopSocketKeepalive(int slot); + void onSignalStrengthThresholdsUpdated(in int[] thresholds); + void onPreventAutomaticReconnect(); + void onAddNattKeepalivePacketFilter(int slot, + in NattKeepalivePacketData packetData); + void onAddTcpKeepalivePacketFilter(int slot, + in TcpKeepalivePacketData packetData); + void onRemoveKeepalivePacketFilter(int slot); + void onQosFilterCallbackRegistered(int qosCallbackId, in QosFilterParcelable filterParcel); + void onQosCallbackUnregistered(int qosCallbackId); +} diff --git a/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl b/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl new file mode 100644 index 000000000000..f0193db5c2e2 --- /dev/null +++ b/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl @@ -0,0 +1,41 @@ +/** + * 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 perNmissions and + * limitations under the License. + */ +package com.android.connectivity.aidl; + +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; +import android.net.QosSession; +import android.telephony.data.EpsBearerQosSessionAttributes; + +/** + * Interface for NetworkAgents to send network network properties. + * @hide + */ +oneway interface INetworkAgentRegistry { + void sendNetworkCapabilities(in NetworkCapabilities nc); + void sendLinkProperties(in LinkProperties lp); + // TODO: consider replacing this by "markConnected()" and removing + void sendNetworkInfo(in NetworkInfo info); + void sendScore(int score); + void sendExplicitlySelected(boolean explicitlySelected, boolean acceptPartial); + void sendSocketKeepaliveEvent(int slot, int reason); + void sendUnderlyingNetworks(in @nullable List<Network> networks); + void sendEpsQosSessionAvailable(int callbackId, in QosSession session, in EpsBearerQosSessionAttributes attributes); + void sendQosSessionLost(int qosCallbackId, in QosSession session); + void sendQosCallbackError(int qosCallbackId, int exceptionType); +} diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java index 35bc490180e8..fcee98d0bd0b 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/BootCompletedReceiver.java @@ -21,7 +21,6 @@ import android.content.Context; import android.content.Intent; import android.os.UserHandle; import android.os.image.DynamicSystemClient; -import android.os.image.DynamicSystemManager; /** @@ -41,15 +40,6 @@ public class BootCompletedReceiver extends BroadcastReceiver { return; } - DynamicSystemManager dynSystem = - (DynamicSystemManager) context.getSystemService(Context.DYNAMIC_SYSTEM_SERVICE); - - boolean isInUse = (dynSystem != null) && dynSystem.isInUse(); - - if (!isInUse) { - return; - } - Intent startServiceIntent = new Intent( context, DynamicSystemInstallationService.class); diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index 6c51f2f42bd4..fbb01bef0e8b 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -249,4 +249,7 @@ <!-- Default for Settings.Secure.ACCESSIBILITY_MAGNIFICATION_CAPABILITY --> <integer name="def_accessibility_magnification_capabilities">3</integer> + + <!-- Default for Settings.Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW --> + <bool name="def_enable_non_resizable_multi_window">false</bool> </resources> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index edb5506cb8cc..c7790fd3ace7 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -3342,7 +3342,7 @@ public class SettingsProvider extends ContentProvider { } private final class UpgradeController { - private static final int SETTINGS_VERSION = 197; + private static final int SETTINGS_VERSION = 198; private final int mUserId; @@ -4815,6 +4815,24 @@ public class SettingsProvider extends ContentProvider { currentVersion = 197; } + if (currentVersion == 197) { + // Version 197: Set the default value for Global Settings: + // DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW + final SettingsState globalSettings = getGlobalSettingsLocked(); + final Setting enableNonResizableMultiWindow = globalSettings.getSettingLocked( + Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW); + if (enableNonResizableMultiWindow.isNull()) { + final boolean defEnableNonResizableMultiWindow = getContext().getResources() + .getBoolean(R.bool.def_enable_non_resizable_multi_window); + globalSettings.insertSettingLocked( + Global.DEVELOPMENT_ENABLE_NON_RESIZABLE_MULTI_WINDOW, + defEnableNonResizableMultiWindow ? "1" : "0", null, true, + SettingsState.SYSTEM_PACKAGE_NAME); + } + + currentVersion = 198; + } + // vXXX: Add new settings above this point. if (currentVersion != newVersion) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java index 1a2a4927c3fd..58ebadeb3f77 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java @@ -23,6 +23,7 @@ import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.RectF; +import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -85,4 +86,12 @@ public class UdfpsAnimationEnroll extends UdfpsAnimation { public int getOpacity() { return 0; } + + public void onEnrollmentProgress(int remaining) { + Log.d(TAG, "Remaining: " + remaining); + } + + public void onEnrollmentHelp() { + Log.d(TAG, "onEnrollmentHelp"); + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index a2b2bea8a06f..001730a7e4fe 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -131,6 +131,16 @@ class UdfpsController implements DozeReceiver { } @Override + public void onEnrollmentProgress(int sensorId, int remaining) { + mView.onEnrollmentProgress(remaining); + } + + @Override + public void onEnrollmentHelp(int sensorId) { + mView.onEnrollmentHelp(); + } + + @Override public void setDebugMessage(int sensorId, String message) { mView.setDebugMessage(message); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java index 4cb8101385ea..983206e7984a 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java @@ -55,7 +55,6 @@ public class UdfpsView extends View implements DozeReceiver { @NonNull private final Paint mSensorPaint; private final float mSensorTouchAreaCoefficient; - // Stores rounded up values from mSensorRect. Necessary for APIs that only take Rect (not RecF). @NonNull private final Rect mTouchableRegion; // mInsetsListener is used to set the touchable region for our window. Our window covers the @@ -281,4 +280,16 @@ public class UdfpsView extends View implements DozeReceiver { mShowScrimAndDot = false; invalidate(); } + + void onEnrollmentProgress(int remaining) { + if (mUdfpsAnimation instanceof UdfpsAnimationEnroll) { + ((UdfpsAnimationEnroll) mUdfpsAnimation).onEnrollmentProgress(remaining); + } + } + + void onEnrollmentHelp() { + if (mUdfpsAnimation instanceof UdfpsAnimationEnroll) { + ((UdfpsAnimationEnroll) mUdfpsAnimation).onEnrollmentHelp(); + } + } } diff --git a/services/OWNERS b/services/OWNERS index f1fa542fca00..03e0807eea62 100644 --- a/services/OWNERS +++ b/services/OWNERS @@ -2,3 +2,5 @@ per-file Android.bp = file:platform/build/soong:/OWNERS # art-team@ manages the system server profile per-file art-profile* = calin@google.com, mathieuc@google.com, ngeoffray@google.com + +per-file java/com/android/server/* = toddke@google.com diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index b6232a0661ff..74a6e07c27f2 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -133,6 +133,7 @@ import android.net.TetheringManager; import android.net.UidRange; import android.net.UidRangeParcel; import android.net.Uri; +import android.net.VpnInfo; import android.net.VpnManager; import android.net.VpnService; import android.net.metrics.INetdEventListener; @@ -184,7 +185,6 @@ import com.android.internal.app.IBatteryStats; import com.android.internal.logging.MetricsLogger; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; -import com.android.internal.net.VpnInfo; import com.android.internal.net.VpnProfile; import com.android.internal.util.ArrayUtils; import com.android.internal.util.AsyncChannel; @@ -325,6 +325,8 @@ public class ConnectivityService extends IConnectivityManager.Stub private boolean mRestrictBackground; private final Context mContext; + // The Context is created for UserHandle.ALL. + private final Context mUserAllContext; private final Dependencies mDeps; // 0 is full bad, 100 is full good private int mDefaultInetConditionPublished = 0; @@ -1160,8 +1162,8 @@ public class ConnectivityService extends IConnectivityManager.Stub intentFilter.addAction(Intent.ACTION_USER_REMOVED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); - final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */); - userAllContext.registerReceiver( + mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */); + mUserAllContext.registerReceiver( mIntentReceiver, intentFilter, null /* broadcastPermission */, @@ -1177,7 +1179,7 @@ public class ConnectivityService extends IConnectivityManager.Stub intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED); intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); intentFilter.addDataScheme("package"); - userAllContext.registerReceiver( + mUserAllContext.registerReceiver( mIntentReceiver, intentFilter, null /* broadcastPermission */, @@ -1186,7 +1188,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // Listen to lockdown VPN reset. intentFilter = new IntentFilter(); intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET); - userAllContext.registerReceiver( + mUserAllContext.registerReceiver( mIntentReceiver, intentFilter, NETWORK_STACK, mHandler); mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mNMS); @@ -1456,9 +1458,8 @@ public class ConnectivityService extends IConnectivityManager.Stub return; } final String action = blocked ? "BLOCKED" : "UNBLOCKED"; - final NetworkRequest satisfiedRequest = nri.getSatisfiedRequest(); - final int requestId = satisfiedRequest != null - ? satisfiedRequest.requestId : nri.mRequests.get(0).requestId; + final int requestId = nri.getActiveRequest() != null + ? nri.getActiveRequest().requestId : nri.mRequests.get(0).requestId; mNetworkInfoBlockingLogs.log(String.format( "%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId())); } @@ -2350,7 +2351,7 @@ public class ConnectivityService extends IConnectivityManager.Stub intent.addFlags(Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); } try { - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL, options); + mUserAllContext.sendStickyBroadcast(intent, options); } finally { Binder.restoreCallingIdentity(ident); } @@ -2728,7 +2729,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @VisibleForTesting NetworkRequestInfo[] requestsSortedById() { NetworkRequestInfo[] requests = new NetworkRequestInfo[0]; - requests = mNetworkRequests.values().toArray(requests); + requests = getNrisFromGlobalRequests().toArray(requests); // Sort the array based off the NRI containing the min requestId in its requests. Arrays.sort(requests, Comparator.comparingInt(nri -> Collections.min(nri.mRequests, @@ -3433,10 +3434,10 @@ public class ConnectivityService extends IConnectivityManager.Stub for (int i = 0; i < nai.numNetworkRequests(); i++) { NetworkRequest request = nai.requestAt(i); final NetworkRequestInfo nri = mNetworkRequests.get(request); - final NetworkAgentInfo currentNetwork = nri.mSatisfier; + final NetworkAgentInfo currentNetwork = nri.getSatisfier(); if (currentNetwork != null && currentNetwork.network.getNetId() == nai.network.getNetId()) { - nri.mSatisfier = null; + nri.setSatisfier(null, null); sendUpdatedScoreToFactories(request, null); } } @@ -3514,42 +3515,63 @@ public class ConnectivityService extends IConnectivityManager.Stub return null; } - private void handleRegisterNetworkRequestWithIntent(Message msg) { + private void handleRegisterNetworkRequestWithIntent(@NonNull final Message msg) { final NetworkRequestInfo nri = (NetworkRequestInfo) (msg.obj); - - NetworkRequestInfo existingRequest = findExistingNetworkRequestInfo(nri.mPendingIntent); + // handleRegisterNetworkRequestWithIntent() doesn't apply to multilayer requests. + ensureNotMultilayerRequest(nri, "handleRegisterNetworkRequestWithIntent"); + final NetworkRequestInfo existingRequest = + findExistingNetworkRequestInfo(nri.mPendingIntent); if (existingRequest != null) { // remove the existing request. - if (DBG) log("Replacing " + existingRequest.request + " with " - + nri.request + " because their intents matched."); - handleReleaseNetworkRequest(existingRequest.request, getCallingUid(), + if (DBG) { + log("Replacing " + existingRequest.mRequests.get(0) + " with " + + nri.mRequests.get(0) + " because their intents matched."); + } + handleReleaseNetworkRequest(existingRequest.mRequests.get(0), getCallingUid(), /* callOnUnavailable */ false); } handleRegisterNetworkRequest(nri); } - private void handleRegisterNetworkRequest(NetworkRequestInfo nri) { + private void handleRegisterNetworkRequest(@NonNull final NetworkRequestInfo nri) { ensureRunningOnConnectivityServiceThread(); - mNetworkRequests.put(nri.request, nri); mNetworkRequestInfoLogs.log("REGISTER " + nri); - if (nri.request.isListen()) { - for (NetworkAgentInfo network : mNetworkAgentInfos) { - if (nri.request.networkCapabilities.hasSignalStrength() && - network.satisfiesImmutableCapabilitiesOf(nri.request)) { - updateSignalStrengthThresholds(network, "REGISTER", nri.request); + for (final NetworkRequest req : nri.mRequests) { + mNetworkRequests.put(req, nri); + if (req.isListen()) { + for (final NetworkAgentInfo network : mNetworkAgentInfos) { + if (req.networkCapabilities.hasSignalStrength() + && network.satisfiesImmutableCapabilitiesOf(req)) { + updateSignalStrengthThresholds(network, "REGISTER", req); + } } } } rematchAllNetworksAndRequests(); - if (nri.request.isRequest() && nri.mSatisfier == null) { - sendUpdatedScoreToFactories(nri.request, null); + // If an active request exists, return as its score has already been sent if needed. + if (null != nri.getActiveRequest()) { + return; + } + + // As this request was not satisfied on rematch and thus never had any scores sent to the + // factories, send null now for each request of type REQUEST. + for (final NetworkRequest req : nri.mRequests) { + if (!req.isRequest()) { + continue; + } + sendUpdatedScoreToFactories(req, null); } } - private void handleReleaseNetworkRequestWithIntent(PendingIntent pendingIntent, - int callingUid) { - NetworkRequestInfo nri = findExistingNetworkRequestInfo(pendingIntent); + private void handleReleaseNetworkRequestWithIntent(@NonNull final PendingIntent pendingIntent, + final int callingUid) { + final NetworkRequestInfo nri = findExistingNetworkRequestInfo(pendingIntent); if (nri != null) { - handleReleaseNetworkRequest(nri.request, callingUid, /* callOnUnavailable */ false); + // handleReleaseNetworkRequestWithIntent() paths don't apply to multilayer requests. + ensureNotMultilayerRequest(nri, "handleReleaseNetworkRequestWithIntent"); + handleReleaseNetworkRequest( + nri.mRequests.get(0), + callingUid, + /* callOnUnavailable */ false); } } @@ -3603,6 +3625,11 @@ public class ConnectivityService extends IConnectivityManager.Stub return false; } for (final NetworkRequest req : nri.mRequests) { + // This multilayer listen request is satisfied therefore no further requests need to be + // evaluated deeming this network not a potential satisfier. + if (req.isListen() && nri.getActiveRequest() == req) { + return false; + } // As non-multilayer listen requests have already returned, the below would only happen // for a multilayer request therefore continue to the next request if available. if (req.isListen()) { @@ -3623,7 +3650,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // 2. Unvalidated WiFi will not be reaped when validated cellular // is currently satisfying the request. This is desirable when // WiFi ends up validating and out scoring cellular. - || nri.mSatisfier.getCurrentScore() + || nri.getSatisfier().getCurrentScore() < candidate.getCurrentScoreAsValidated(); return isNetworkNeeded; } @@ -3648,30 +3675,45 @@ public class ConnectivityService extends IConnectivityManager.Stub return nri; } - private void handleTimedOutNetworkRequest(final NetworkRequestInfo nri) { + private void ensureNotMultilayerRequest(@NonNull final NetworkRequestInfo nri, + final String callingMethod) { + if (nri.isMultilayerRequest()) { + throw new IllegalStateException( + callingMethod + " does not support multilayer requests."); + } + } + + private void handleTimedOutNetworkRequest(@NonNull final NetworkRequestInfo nri) { ensureRunningOnConnectivityServiceThread(); - if (mNetworkRequests.get(nri.request) == null) { + // handleTimedOutNetworkRequest() is part of the requestNetwork() flow which works off of a + // single NetworkRequest and thus does not apply to multilayer requests. + ensureNotMultilayerRequest(nri, "handleTimedOutNetworkRequest"); + if (mNetworkRequests.get(nri.mRequests.get(0)) == null) { return; } - if (nri.mSatisfier != null) { + if (nri.getSatisfier() != null) { return; } - if (VDBG || (DBG && nri.request.isRequest())) { - log("releasing " + nri.request + " (timeout)"); + if (VDBG || (DBG && nri.mRequests.get(0).isRequest())) { + log("releasing " + nri.mRequests.get(0) + " (timeout)"); } handleRemoveNetworkRequest(nri); - callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0); + callCallbackForRequest( + nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0); } - private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid, - boolean callOnUnavailable) { + private void handleReleaseNetworkRequest(@NonNull final NetworkRequest request, + final int callingUid, + final boolean callOnUnavailable) { final NetworkRequestInfo nri = getNriForAppRequest(request, callingUid, "release NetworkRequest"); if (nri == null) { return; } - if (VDBG || (DBG && nri.request.isRequest())) { - log("releasing " + nri.request + " (release request)"); + // handleReleaseNetworkRequest() paths don't apply to multilayer requests. + ensureNotMultilayerRequest(nri, "handleReleaseNetworkRequest"); + if (VDBG || (DBG && request.isRequest())) { + log("releasing " + request + " (release request)"); } handleRemoveNetworkRequest(nri); if (callOnUnavailable) { @@ -3679,42 +3721,88 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private void handleRemoveNetworkRequest(final NetworkRequestInfo nri) { + private void handleRemoveNetworkRequest(@NonNull final NetworkRequestInfo nri) { ensureRunningOnConnectivityServiceThread(); nri.unlinkDeathRecipient(); - mNetworkRequests.remove(nri.request); - + for (final NetworkRequest req : nri.mRequests) { + mNetworkRequests.remove(req); + if (req.isListen()) { + removeListenRequestFromNetworks(req); + } + } mNetworkRequestCounter.decrementCount(nri.mUid); - mNetworkRequestInfoLogs.log("RELEASE " + nri); - if (nri.request.isRequest()) { - boolean wasKept = false; - final NetworkAgentInfo nai = nri.mSatisfier; - if (nai != null) { - boolean wasBackgroundNetwork = nai.isBackgroundNetwork(); - nai.removeRequest(nri.request.requestId); - if (VDBG || DDBG) { - log(" Removing from current network " + nai.toShortString() - + ", leaving " + nai.numNetworkRequests() + " requests."); - } - // If there are still lingered requests on this network, don't tear it down, - // but resume lingering instead. - final long now = SystemClock.elapsedRealtime(); - if (updateLingerState(nai, now)) { - notifyNetworkLosing(nai, now); - } - if (unneeded(nai, UnneededFor.TEARDOWN)) { - if (DBG) log("no live requests for " + nai.toShortString() + "; disconnecting"); - teardownUnneededNetwork(nai); - } else { - wasKept = true; - } - nri.mSatisfier = null; - if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) { - // Went from foreground to background. - updateCapabilitiesForNetwork(nai); - } + + if (null != nri.getActiveRequest()) { + if (nri.getActiveRequest().isRequest()) { + removeSatisfiedNetworkRequestFromNetwork(nri); + } else { + nri.setSatisfier(null, null); + } + } + + cancelNpiRequests(nri); + } + + private void cancelNpiRequests(@NonNull final NetworkRequestInfo nri) { + for (final NetworkRequest req : nri.mRequests) { + cancelNpiRequest(req); + } + } + + private void cancelNpiRequest(@NonNull final NetworkRequest req) { + if (req.isRequest()) { + for (final NetworkProviderInfo npi : mNetworkProviderInfos.values()) { + npi.cancelRequest(req); + } + } + } + + private void removeListenRequestFromNetworks(@NonNull final NetworkRequest req) { + // listens don't have a singular affected Network. Check all networks to see + // if this listen request applies and remove it. + for (final NetworkAgentInfo nai : mNetworkAgentInfos) { + nai.removeRequest(req.requestId); + if (req.networkCapabilities.hasSignalStrength() + && nai.satisfiesImmutableCapabilitiesOf(req)) { + updateSignalStrengthThresholds(nai, "RELEASE", req); + } + } + } + + /** + * Remove a NetworkRequestInfo's satisfied request from its 'satisfier' (NetworkAgentInfo) and + * manage the necessary upkeep (linger, teardown networks, etc.) when doing so. + * @param nri the NetworkRequestInfo to disassociate from its current NetworkAgentInfo + */ + private void removeSatisfiedNetworkRequestFromNetwork(@NonNull final NetworkRequestInfo nri) { + boolean wasKept = false; + final NetworkAgentInfo nai = nri.getSatisfier(); + if (nai != null) { + final int requestLegacyType = nri.getActiveRequest().legacyType; + final boolean wasBackgroundNetwork = nai.isBackgroundNetwork(); + nai.removeRequest(nri.getActiveRequest().requestId); + if (VDBG || DDBG) { + log(" Removing from current network " + nai.toShortString() + + ", leaving " + nai.numNetworkRequests() + " requests."); + } + // If there are still lingered requests on this network, don't tear it down, + // but resume lingering instead. + final long now = SystemClock.elapsedRealtime(); + if (updateLingerState(nai, now)) { + notifyNetworkLosing(nai, now); + } + if (unneeded(nai, UnneededFor.TEARDOWN)) { + if (DBG) log("no live requests for " + nai.toShortString() + "; disconnecting"); + teardownUnneededNetwork(nai); + } else { + wasKept = true; + } + nri.setSatisfier(null, null); + if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) { + // Went from foreground to background. + updateCapabilitiesForNetwork(nai); } // Maintain the illusion. When this request arrived, we might have pretended @@ -3722,15 +3810,15 @@ public class ConnectivityService extends IConnectivityManager.Stub // connected. Now that this request has gone away, we might have to pretend // that the network disconnected. LegacyTypeTracker will generate that // phantom disconnect for this type. - if (nri.request.legacyType != TYPE_NONE && nai != null) { + if (requestLegacyType != TYPE_NONE) { boolean doRemove = true; if (wasKept) { // check if any of the remaining requests for this network are for the // same legacy type - if so, don't remove the nai for (int i = 0; i < nai.numNetworkRequests(); i++) { NetworkRequest otherRequest = nai.requestAt(i); - if (otherRequest.legacyType == nri.request.legacyType && - otherRequest.isRequest()) { + if (otherRequest.legacyType == requestLegacyType + && otherRequest.isRequest()) { if (DBG) log(" still have other legacy request - leaving"); doRemove = false; } @@ -3738,21 +3826,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } if (doRemove) { - mLegacyTypeTracker.remove(nri.request.legacyType, nai, false); - } - } - - for (NetworkProviderInfo npi : mNetworkProviderInfos.values()) { - npi.cancelRequest(nri.request); - } - } else { - // listens don't have a singular affectedNetwork. Check all networks to see - // if this listen request applies and remove it. - for (NetworkAgentInfo nai : mNetworkAgentInfos) { - nai.removeRequest(nri.request.requestId); - if (nri.request.networkCapabilities.hasSignalStrength() && - nai.satisfiesImmutableCapabilitiesOf(nri.request)) { - updateSignalStrengthThresholds(nai, "RELEASE", nri.request); + mLegacyTypeTracker.remove(requestLegacyType, nai, false); } } } @@ -4830,16 +4904,14 @@ public class ConnectivityService extends IConnectivityManager.Stub if (interfaces.isEmpty()) return null; - VpnInfo info = new VpnInfo(); - info.ownerUid = nai.networkCapabilities.getOwnerUid(); - info.vpnIface = nai.linkProperties.getInterfaceName(); // Must be non-null or NetworkStatsService will crash. // Cannot happen in production code because Vpn only registers the NetworkAgent after the // tun or ipsec interface is created. - if (info.vpnIface == null) return null; - info.underlyingIfaces = interfaces.toArray(new String[0]); + if (nai.linkProperties.getInterfaceName() == null) return null; - return info; + return new VpnInfo(nai.networkCapabilities.getOwnerUid(), + nai.linkProperties.getInterfaceName(), + interfaces.toArray(new String[0])); } /** @@ -5415,18 +5487,38 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * Tracks info about the requester. - * Also used to notice when the calling process dies so we can self-expire + * Also used to notice when the calling process dies so as to self-expire */ @VisibleForTesting protected class NetworkRequestInfo implements IBinder.DeathRecipient { final List<NetworkRequest> mRequests; - final NetworkRequest request; + + // mSatisfier and mActiveRequest rely on one another therefore set them together. + void setSatisfier( + @Nullable final NetworkAgentInfo satisfier, + @Nullable final NetworkRequest activeRequest) { + mSatisfier = satisfier; + mActiveRequest = activeRequest; + } // The network currently satisfying this request, or null if none. Must only be touched // on the handler thread. This only makes sense for network requests and not for listens, // as defined by NetworkRequest#isRequest(). For listens, this is always null. @Nullable - NetworkAgentInfo mSatisfier; + private NetworkAgentInfo mSatisfier; + NetworkAgentInfo getSatisfier() { + return mSatisfier; + } + + // The request in mRequests assigned to a network agent. This is null if none of the + // requests in mRequests can be satisfied. This member has the constraint of only being + // accessible on the handler thread. + @Nullable + private NetworkRequest mActiveRequest; + NetworkRequest getActiveRequest() { + return mActiveRequest; + } + final PendingIntent mPendingIntent; boolean mPendingIntentSent; private final IBinder mBinder; @@ -5435,7 +5527,6 @@ public class ConnectivityService extends IConnectivityManager.Stub final Messenger messenger; NetworkRequestInfo(NetworkRequest r, PendingIntent pi) { - request = r; mRequests = initializeRequests(r); ensureAllNetworkRequestsHaveType(mRequests); mPendingIntent = pi; @@ -5449,7 +5540,6 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder) { super(); messenger = m; - request = r; mRequests = initializeRequests(r); ensureAllNetworkRequestsHaveType(mRequests); mBinder = binder; @@ -5479,20 +5569,6 @@ public class ConnectivityService extends IConnectivityManager.Stub return Collections.unmodifiableList(tempRequests); } - private NetworkRequest getSatisfiedRequest() { - if (mSatisfier == null) { - return null; - } - - for (NetworkRequest req : mRequests) { - if (mSatisfier.isSatisfyingRequest(req.requestId)) { - return req; - } - } - - return null; - } - void unlinkDeathRecipient() { if (mBinder != null) { mBinder.unlinkToDeath(this, 0); @@ -5539,6 +5615,10 @@ public class ConnectivityService extends IConnectivityManager.Stub private int[] getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) { final SortedSet<Integer> thresholds = new TreeSet<>(); synchronized (nai) { + // mNetworkRequests may contain the same value multiple times in case of + // multilayer requests. It won't matter in this case because the thresholds + // will then be the same and be deduplicated as they enter the `thresholds` set. + // TODO : have mNetworkRequests be a Set<NetworkRequestInfo> or the like. for (final NetworkRequestInfo nri : mNetworkRequests.values()) { for (final NetworkRequest req : nri.mRequests) { if (req.networkCapabilities.hasSignalStrength() @@ -5914,13 +5994,19 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public void declareNetworkRequestUnfulfillable(NetworkRequest request) { + public void declareNetworkRequestUnfulfillable(@NonNull final NetworkRequest request) { if (request.hasTransport(TRANSPORT_TEST)) { enforceNetworkFactoryOrTestNetworksPermission(); } else { enforceNetworkFactoryPermission(); } - mHandler.post(() -> handleReleaseNetworkRequest(request, mDeps.getCallingUid(), true)); + final NetworkRequestInfo nri = mNetworkRequests.get(request); + if (nri != null) { + // declareNetworkRequestUnfulfillable() paths don't apply to multilayer requests. + ensureNotMultilayerRequest(nri, "declareNetworkRequestUnfulfillable"); + mHandler.post(() -> handleReleaseNetworkRequest( + nri.mRequests.get(0), mDeps.getCallingUid(), true)); + } } // NOTE: Accessed on multiple threads, must be synchronized on itself. @@ -6845,6 +6931,39 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private void sendUpdatedScoreToFactories( + @NonNull final NetworkReassignment.RequestReassignment event) { + // If a request of type REQUEST is now being satisfied by a new network. + if (null != event.mNewNetworkRequest && event.mNewNetworkRequest.isRequest()) { + sendUpdatedScoreToFactories(event.mNewNetworkRequest, event.mNewNetwork); + } + + // If a previously satisfied request of type REQUEST is no longer being satisfied. + if (null != event.mOldNetworkRequest && event.mOldNetworkRequest.isRequest() + && event.mOldNetworkRequest != event.mNewNetworkRequest) { + sendUpdatedScoreToFactories(event.mOldNetworkRequest, null); + } + + cancelMultilayerLowerPriorityNpiRequests(event.mNetworkRequestInfo); + } + + /** + * Cancel with all NPIs the given NRI's multilayer requests that are a lower priority than + * its currently satisfied active request. + * @param nri the NRI to cancel lower priority requests for. + */ + private void cancelMultilayerLowerPriorityNpiRequests( + @NonNull final NetworkRequestInfo nri) { + if (!nri.isMultilayerRequest() || null == nri.mActiveRequest) { + return; + } + + final int indexOfNewRequest = nri.mRequests.indexOf(nri.mActiveRequest); + for (int i = indexOfNewRequest + 1; i < nri.mRequests.size(); i++) { + cancelNpiRequest(nri.mRequests.get(i)); + } + } + private void sendUpdatedScoreToFactories(@NonNull NetworkRequest networkRequest, @Nullable NetworkAgentInfo nai) { final int score; @@ -6865,21 +6984,35 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** Sends all current NetworkRequests to the specified factory. */ - private void sendAllRequestsToProvider(NetworkProviderInfo npi) { + private void sendAllRequestsToProvider(@NonNull final NetworkProviderInfo npi) { 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 = NetworkProvider.ID_NONE; + for (final NetworkRequestInfo nri : getNrisFromGlobalRequests()) { + for (final NetworkRequest req : nri.mRequests) { + if (req.isListen() && nri.getActiveRequest() == req) { + break; + } + if (req.isListen()) { + continue; + } + // Only set the nai for the request it is satisfying. + final NetworkAgentInfo nai = + nri.getActiveRequest() == req ? nri.getSatisfier() : null; + final int score; + final int serial; + if (null != nai) { + score = nai.getCurrentScore(); + serial = nai.factorySerialNumber; + } else { + score = 0; + serial = NetworkProvider.ID_NONE; + } + npi.requestNetwork(req, score, serial); + // For multilayer requests, don't send lower priority requests if a higher priority + // request is already satisfied. + if (null != nai) { + break; + } } - npi.requestNetwork(nri.request, score, serial); } } @@ -6888,7 +7021,12 @@ public class ConnectivityService extends IConnectivityManager.Stub if (notificationType == ConnectivityManager.CALLBACK_AVAILABLE && !nri.mPendingIntentSent) { Intent intent = new Intent(); intent.putExtra(ConnectivityManager.EXTRA_NETWORK, networkAgent.network); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_REQUEST, nri.request); + // If apps could file multi-layer requests with PendingIntents, they'd need to know + // which of the layer is satisfied alongside with some ID for the request. Hence, if + // such an API is ever implemented, there is no doubt the right request to send in + // EXTRA_NETWORK_REQUEST is mActiveRequest, and whatever ID would be added would need to + // be sent as a separate extra. + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_REQUEST, nri.getActiveRequest()); nri.mPendingIntentSent = true; sendIntent(nri.mPendingIntent, intent); } @@ -6918,8 +7056,9 @@ public class ConnectivityService extends IConnectivityManager.Stub releasePendingNetworkRequestWithDelay(pendingIntent); } - private void callCallbackForRequest(NetworkRequestInfo nri, - NetworkAgentInfo networkAgent, int notificationType, int arg1) { + private void callCallbackForRequest(@NonNull final NetworkRequestInfo nri, + @NonNull final NetworkAgentInfo networkAgent, final int notificationType, + final int arg1) { if (nri.messenger == null) { // Default request has no msgr. Also prevents callbacks from being invoked for // NetworkRequestInfos registered with ConnectivityDiagnostics requests. Those callbacks @@ -6927,8 +7066,14 @@ public class ConnectivityService extends IConnectivityManager.Stub return; } Bundle bundle = new Bundle(); + // In the case of multi-layer NRIs, the first request is not necessarily the one that + // is satisfied. This is vexing, but the ConnectivityManager code that receives this + // callback is only using the request as a token to identify the callback, so it doesn't + // matter too much at this point as long as the callback can be found. + // TODO b/177608132: make sure callbacks are indexed by NRIs and not NetworkRequest objects. // TODO: check if defensive copies of data is needed. - putParcelable(bundle, new NetworkRequest(nri.request)); + final NetworkRequest nrForCallback = new NetworkRequest(nri.mRequests.get(0)); + putParcelable(bundle, nrForCallback); Message msg = Message.obtain(); if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL) { putParcelable(bundle, networkAgent.network); @@ -6941,7 +7086,7 @@ public class ConnectivityService extends IConnectivityManager.Stub putParcelable( bundle, createWithLocationInfoSanitizedIfNecessaryWhenParceled( - nc, nri.mUid, nri.request.getRequestorPackageName())); + nc, nri.mUid, nrForCallback.getRequestorPackageName())); putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions( networkAgent.linkProperties, nri.mPid, nri.mUid)); // For this notification, arg1 contains the blocked status. @@ -6960,7 +7105,7 @@ public class ConnectivityService extends IConnectivityManager.Stub putParcelable( bundle, createWithLocationInfoSanitizedIfNecessaryWhenParceled( - netCap, nri.mUid, nri.request.getRequestorPackageName())); + netCap, nri.mUid, nrForCallback.getRequestorPackageName())); break; } case ConnectivityManager.CALLBACK_IP_CHANGED: { @@ -6979,12 +7124,12 @@ public class ConnectivityService extends IConnectivityManager.Stub try { if (VDBG) { String notification = ConnectivityManager.getCallbackName(notificationType); - log("sending notification " + notification + " for " + nri.request); + log("sending notification " + notification + " for " + nrForCallback); } nri.messenger.send(msg); } catch (RemoteException e) { // may occur naturally in the race of binder death. - loge("RemoteException caught trying to send a callback msg for " + nri.request); + loge("RemoteException caught trying to send a callback msg for " + nrForCallback); } } @@ -7060,19 +7205,25 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void processNewlyLostListenRequests(@NonNull final NetworkAgentInfo nai) { - for (NetworkRequestInfo nri : mNetworkRequests.values()) { - NetworkRequest nr = nri.request; + for (final NetworkRequestInfo nri : mNetworkRequests.values()) { + if (nri.isMultilayerRequest()) { + continue; + } + final NetworkRequest nr = nri.mRequests.get(0); if (!nr.isListen()) continue; if (nai.isSatisfyingRequest(nr.requestId) && !nai.satisfies(nr)) { - nai.removeRequest(nri.request.requestId); + nai.removeRequest(nr.requestId); callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_LOST, 0); } } } private void processNewlySatisfiedListenRequests(@NonNull final NetworkAgentInfo nai) { - for (NetworkRequestInfo nri : mNetworkRequests.values()) { - NetworkRequest nr = nri.request; + for (final NetworkRequestInfo nri : mNetworkRequests.values()) { + if (nri.isMultilayerRequest()) { + continue; + } + final NetworkRequest nr = nri.mRequests.get(0); if (!nr.isListen()) continue; if (nai.satisfies(nr) && !nai.isSatisfyingRequest(nr.requestId)) { nai.addRequest(nr); @@ -7084,19 +7235,25 @@ public class ConnectivityService extends IConnectivityManager.Stub // An accumulator class to gather the list of changes that result from a rematch. private static class NetworkReassignment { static class RequestReassignment { - @NonNull public final NetworkRequestInfo mRequest; + @NonNull public final NetworkRequestInfo mNetworkRequestInfo; + @NonNull public final NetworkRequest mOldNetworkRequest; + @NonNull public final NetworkRequest mNewNetworkRequest; @Nullable public final NetworkAgentInfo mOldNetwork; @Nullable public final NetworkAgentInfo mNewNetwork; - RequestReassignment(@NonNull final NetworkRequestInfo request, + RequestReassignment(@NonNull final NetworkRequestInfo networkRequestInfo, + @NonNull final NetworkRequest oldNetworkRequest, + @NonNull final NetworkRequest newNetworkRequest, @Nullable final NetworkAgentInfo oldNetwork, @Nullable final NetworkAgentInfo newNetwork) { - mRequest = request; + mNetworkRequestInfo = networkRequestInfo; + mOldNetworkRequest = oldNetworkRequest; + mNewNetworkRequest = newNetworkRequest; mOldNetwork = oldNetwork; mNewNetwork = newNetwork; } public String toString() { - return mRequest.mRequests.get(0).requestId + " : " + return mNetworkRequestInfo.mRequests.get(0).requestId + " : " + (null != mOldNetwork ? mOldNetwork.network.getNetId() : "null") + " → " + (null != mNewNetwork ? mNewNetwork.network.getNetId() : "null"); } @@ -7114,7 +7271,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // sure this stays true, but without imposing this expensive check on all // reassignments on all user devices. for (final RequestReassignment existing : mReassignments) { - if (existing.mRequest.equals(reassignment.mRequest)) { + if (existing.mNetworkRequestInfo.equals(reassignment.mNetworkRequestInfo)) { throw new IllegalStateException("Trying to reassign [" + reassignment + "] but already have [" + existing + "]"); @@ -7129,7 +7286,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Nullable private RequestReassignment getReassignment(@NonNull final NetworkRequestInfo nri) { for (final RequestReassignment event : getRequestReassignments()) { - if (nri == event.mRequest) return event; + if (nri == event.mNetworkRequestInfo) return event; } return null; } @@ -7156,6 +7313,8 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void updateSatisfiersForRematchRequest(@NonNull final NetworkRequestInfo nri, + @NonNull final NetworkRequest previousRequest, + @NonNull final NetworkRequest newRequest, @Nullable final NetworkAgentInfo previousSatisfier, @Nullable final NetworkAgentInfo newSatisfier, final long now) { @@ -7165,58 +7324,98 @@ public class ConnectivityService extends IConnectivityManager.Stub if (VDBG || DDBG) { log(" accepting network in place of " + previousSatisfier.toShortString()); } - previousSatisfier.removeRequest(nri.request.requestId); - previousSatisfier.lingerRequest(nri.request.requestId, now, mLingerDelayMs); + previousSatisfier.removeRequest(previousRequest.requestId); + previousSatisfier.lingerRequest(previousRequest.requestId, now, mLingerDelayMs); } else { if (VDBG || DDBG) log(" accepting network in place of null"); } - newSatisfier.unlingerRequest(nri.request.requestId); - if (!newSatisfier.addRequest(nri.request)) { + newSatisfier.unlingerRequest(newRequest.requestId); + if (!newSatisfier.addRequest(newRequest)) { Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has " - + nri.request); + + newRequest); } } else { if (DBG) { log("Network " + previousSatisfier.toShortString() + " stopped satisfying" - + " request " + nri.request.requestId); + + " request " + previousRequest.requestId); } - previousSatisfier.removeRequest(nri.request.requestId); + previousSatisfier.removeRequest(previousRequest.requestId); } - nri.mSatisfier = newSatisfier; + nri.setSatisfier(newSatisfier, newRequest); } + /** + * This function is triggered when something can affect what network should satisfy what + * request, and it computes the network reassignment from the passed collection of requests to + * network match to the one that the system should now have. That data is encoded in an + * object that is a list of changes, each of them having an NRI, and old satisfier, and a new + * satisfier. + * + * After the reassignment is computed, it is applied to the state objects. + * + * @param networkRequests the nri objects to evaluate for possible network reassignment + * @return NetworkReassignment listing of proposed network assignment changes + */ @NonNull - private NetworkReassignment computeNetworkReassignment() { - ensureRunningOnConnectivityServiceThread(); + private NetworkReassignment computeNetworkReassignment( + @NonNull final Collection<NetworkRequestInfo> networkRequests) { final NetworkReassignment changes = new NetworkReassignment(); // Gather the list of all relevant agents and sort them by score. final ArrayList<NetworkAgentInfo> nais = new ArrayList<>(); for (final NetworkAgentInfo nai : mNetworkAgentInfos) { - if (!nai.everConnected) continue; + if (!nai.everConnected) { + continue; + } nais.add(nai); } - for (final NetworkRequestInfo nri : mNetworkRequests.values()) { - if (nri.request.isListen()) continue; - final NetworkAgentInfo bestNetwork = mNetworkRanker.getBestNetwork(nri.request, nais); + for (final NetworkRequestInfo nri : networkRequests) { + // Non-multilayer listen requests can be ignored. + if (!nri.isMultilayerRequest() && nri.mRequests.get(0).isListen()) { + continue; + } + NetworkAgentInfo bestNetwork = null; + NetworkRequest bestRequest = null; + for (final NetworkRequest req : nri.mRequests) { + bestNetwork = mNetworkRanker.getBestNetwork(req, nais); + // Stop evaluating as the highest possible priority request is satisfied. + if (null != bestNetwork) { + bestRequest = req; + break; + } + } if (bestNetwork != nri.mSatisfier) { // bestNetwork may be null if no network can satisfy this request. changes.addRequestReassignment(new NetworkReassignment.RequestReassignment( - nri, nri.mSatisfier, bestNetwork)); + nri, nri.mActiveRequest, bestRequest, nri.getSatisfier(), bestNetwork)); } } return changes; } + private Set<NetworkRequestInfo> getNrisFromGlobalRequests() { + return new HashSet<>(mNetworkRequests.values()); + } + /** - * Attempt to rematch all Networks with NetworkRequests. This may result in Networks + * Attempt to rematch all Networks with all NetworkRequests. This may result in Networks * being disconnected. */ private void rematchAllNetworksAndRequests() { + rematchNetworksAndRequests(getNrisFromGlobalRequests()); + } + + /** + * Attempt to rematch all Networks with given NetworkRequests. This may result in Networks + * being disconnected. + */ + private void rematchNetworksAndRequests( + @NonNull final Set<NetworkRequestInfo> networkRequests) { + ensureRunningOnConnectivityServiceThread(); // TODO: This may be slow, and should be optimized. final long now = SystemClock.elapsedRealtime(); - final NetworkReassignment changes = computeNetworkReassignment(); + final NetworkReassignment changes = computeNetworkReassignment(networkRequests); if (VDBG || DDBG) { log(changes.debugString()); } else if (DBG) { @@ -7241,8 +7440,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // the linger status. for (final NetworkReassignment.RequestReassignment event : changes.getRequestReassignments()) { - updateSatisfiersForRematchRequest(event.mRequest, event.mOldNetwork, - event.mNewNetwork, now); + updateSatisfiersForRematchRequest(event.mNetworkRequestInfo, + event.mOldNetworkRequest, event.mNewNetworkRequest, + event.mOldNetwork, event.mNewNetwork, + now); } final NetworkAgentInfo oldDefaultNetwork = getDefaultNetwork(); @@ -7294,12 +7495,12 @@ public class ConnectivityService extends IConnectivityManager.Stub // trying to connect if they know they cannot match it. // TODO - this could get expensive if there are a lot of outstanding requests for this // network. Think of a way to reduce this. Push netid->request mapping to each factory? - sendUpdatedScoreToFactories(event.mRequest.request, event.mNewNetwork); + sendUpdatedScoreToFactories(event); if (null != event.mNewNetwork) { - notifyNetworkAvailable(event.mNewNetwork, event.mRequest); + notifyNetworkAvailable(event.mNewNetwork, event.mNetworkRequestInfo); } else { - callCallbackForRequest(event.mRequest, event.mOldNetwork, + callCallbackForRequest(event.mNetworkRequestInfo, event.mOldNetwork, ConnectivityManager.CALLBACK_LOST, 0); } } diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java index f2b63a642c29..88ce2208adcb 100644 --- a/services/core/java/com/android/server/DynamicSystemService.java +++ b/services/core/java/com/android/server/DynamicSystemService.java @@ -22,7 +22,6 @@ import android.gsi.AvbPublicKey; import android.gsi.GsiProgress; import android.gsi.IGsiService; import android.gsi.IGsiServiceCallback; -import android.os.Environment; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; @@ -30,7 +29,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.image.IDynamicSystemService; import android.os.storage.StorageManager; -import android.os.storage.StorageVolume; +import android.os.storage.VolumeInfo; import android.util.Slog; import java.io.File; @@ -88,16 +87,17 @@ public class DynamicSystemService extends IDynamicSystemService.Stub { String path = SystemProperties.get("os.aot.path"); if (path.isEmpty()) { final int userId = UserHandle.myUserId(); - final StorageVolume[] volumes = - StorageManager.getVolumeList(userId, StorageManager.FLAG_FOR_WRITE); - for (StorageVolume volume : volumes) { - if (volume.isEmulated()) continue; - if (!volume.isRemovable()) continue; - if (!Environment.MEDIA_MOUNTED.equals(volume.getState())) continue; - File sdCard = volume.getPathFile(); - if (sdCard.isDirectory()) { - path = new File(sdCard, dsuSlot).getPath(); - break; + final StorageManager sm = mContext.getSystemService(StorageManager.class); + for (VolumeInfo volume : sm.getVolumes()) { + if (volume.getType() != volume.TYPE_PUBLIC) { + continue; + } + if (!volume.isMountedWritable()) { + continue; + } + File sd_internal = volume.getInternalPathForUser(userId); + if (sd_internal != null) { + path = new File(sd_internal, dsuSlot).getPath(); } } if (path.isEmpty()) { diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index cd6a9fb447c9..0412f08d3ae3 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -3136,6 +3136,12 @@ class StorageManagerService extends IStorageManager.Stub enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); if (isFsEncrypted) { + // When a user has secure lock screen, require secret to actually unlock. + // This check is mostly in place for emulation mode. + if (StorageManager.isFileEncryptedEmulatedOnly() && + mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(secret)) { + throw new IllegalStateException("Secret required to unlock secure user " + userId); + } try { mVold.unlockUserKey(userId, serialNumber, encodeBytes(token), encodeBytes(secret)); diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index ba1eda99db10..efe82df628d2 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -715,7 +715,7 @@ public class Watchdog { WatchdogDiagnostics.diagnoseCheckers(blockedCheckers); Slog.w(TAG, "*** GOODBYE!"); if (!Build.IS_USER && isCrashLoopFound() - && !WatchdogProperties.is_fatal_ignore().orElse(false)) { + && !WatchdogProperties.should_ignore_fatal_count().orElse(false)) { breakCrashLoop(); } Process.killProcess(Process.myPid()); @@ -794,7 +794,7 @@ public class Watchdog { private boolean isCrashLoopFound() { int fatalCount = WatchdogProperties.fatal_count().orElse(0); long fatalWindowMs = TimeUnit.SECONDS.toMillis( - WatchdogProperties.fatal_window_second().orElse(0)); + WatchdogProperties.fatal_window_seconds().orElse(0)); if (fatalCount == 0 || fatalWindowMs == 0) { if (fatalCount != fatalWindowMs) { Slog.w(TAG, String.format("sysprops '%s' and '%s' should be set or unset together", diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java new file mode 100644 index 000000000000..508bb01e50a8 --- /dev/null +++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java @@ -0,0 +1,349 @@ +/* + * Copyright (C) 2021 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.apphibernation; + +import static android.content.Intent.ACTION_PACKAGE_ADDED; +import static android.content.Intent.ACTION_PACKAGE_REMOVED; +import static android.content.Intent.ACTION_USER_ADDED; +import static android.content.Intent.ACTION_USER_REMOVED; +import static android.content.Intent.EXTRA_REPLACING; +import static android.content.pm.PackageManager.MATCH_ALL; +import static android.provider.DeviceConfig.NAMESPACE_APP_HIBERNATION; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.IActivityManager; +import android.apphibernation.IAppHibernationService; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.IPackageManager; +import android.content.pm.PackageInfo; +import android.content.pm.UserInfo; +import android.os.Binder; +import android.os.RemoteException; +import android.os.ResultReceiver; +import android.os.ServiceManager; +import android.os.ShellCallback; +import android.os.Trace; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.DeviceConfig; +import android.util.ArrayMap; +import android.util.SparseArray; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.SystemService; + +import java.io.FileDescriptor; +import java.util.List; +import java.util.Map; + +/** + * System service that manages app hibernation state, a state apps can enter that means they are + * not being actively used and can be optimized for storage. The actual policy for determining + * if an app should hibernate is managed by PermissionController code. + */ +public final class AppHibernationService extends SystemService { + private static final String TAG = "AppHibernationService"; + + /** + * Lock for accessing any in-memory hibernation state + */ + private final Object mLock = new Object(); + private final Context mContext; + private final IPackageManager mIPackageManager; + private final IActivityManager mIActivityManager; + private final UserManager mUserManager; + @GuardedBy("mLock") + private final SparseArray<Map<String, UserPackageState>> mUserStates = new SparseArray<>(); + + /** + * Initializes the system service. + * <p> + * Subclasses must define a single argument constructor that accepts the context + * and passes it to super. + * </p> + * + * @param context The system server context. + */ + public AppHibernationService(@NonNull Context context) { + this(context, IPackageManager.Stub.asInterface(ServiceManager.getService("package")), + ActivityManager.getService(), + context.getSystemService(UserManager.class)); + } + + @VisibleForTesting + AppHibernationService(@NonNull Context context, IPackageManager packageManager, + IActivityManager activityManager, UserManager userManager) { + super(context); + mContext = context; + mIPackageManager = packageManager; + mIActivityManager = activityManager; + mUserManager = userManager; + + final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */); + + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ACTION_USER_ADDED); + intentFilter.addAction(ACTION_USER_REMOVED); + userAllContext.registerReceiver(mBroadcastReceiver, intentFilter); + + intentFilter = new IntentFilter(); + intentFilter.addAction(ACTION_PACKAGE_ADDED); + intentFilter.addAction(ACTION_PACKAGE_REMOVED); + intentFilter.addDataScheme("package"); + userAllContext.registerReceiver(mBroadcastReceiver, intentFilter); + } + + @Override + public void onStart() { + publishBinderService(Context.APP_HIBERNATION_SERVICE, mServiceStub); + } + + @Override + public void onBootPhase(int phase) { + if (phase == PHASE_BOOT_COMPLETED) { + synchronized (mLock) { + final List<UserInfo> users = mUserManager.getUsers(); + // TODO: Pull from persistent disk storage. For now, just make from scratch. + for (UserInfo user : users) { + addUserPackageStatesL(user.id); + } + } + } + } + + /** + * Whether a package is hibernating for a given user. + * + * @param packageName the package to check + * @param userId the user to check + * @return true if package is hibernating for the user + */ + public boolean isHibernating(String packageName, int userId) { + userId = handleIncomingUser(userId, "isHibernating"); + synchronized (mLock) { + final Map<String, UserPackageState> packageStates = mUserStates.get(userId); + if (packageStates == null) { + throw new IllegalArgumentException("No user associated with user id " + userId); + } + final UserPackageState pkgState = packageStates.get(packageName); + if (pkgState == null) { + throw new IllegalArgumentException( + String.format("Package %s is not installed for user %s", + packageName, userId)); + } + return pkgState != null ? pkgState.hibernated : null; + } + } + + /** + * Set whether the package is hibernating for the given user. + * + * @param packageName package to modify state + * @param userId user + * @param isHibernating new hibernation state + */ + public void setHibernating(String packageName, int userId, boolean isHibernating) { + userId = handleIncomingUser(userId, "setHibernating"); + synchronized (mLock) { + if (!mUserStates.contains(userId)) { + throw new IllegalArgumentException("No user associated with user id " + userId); + } + Map<String, UserPackageState> packageStates = mUserStates.get(userId); + UserPackageState pkgState = packageStates.get(packageName); + if (pkgState == null) { + throw new IllegalArgumentException( + String.format("Package %s is not installed for user %s", + packageName, userId)); + } + + if (pkgState.hibernated == isHibernating) { + return; + } + + + final long caller = Binder.clearCallingIdentity(); + try { + if (isHibernating) { + Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "hibernatePackage"); + mIActivityManager.forceStopPackage(packageName, userId); + mIPackageManager.deleteApplicationCacheFilesAsUser(packageName, userId, + null /* observer */); + } else { + Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "unhibernatePackage"); + mIPackageManager.setPackageStoppedState(packageName, false, userId); + } + pkgState.hibernated = isHibernating; + } catch (RemoteException e) { + throw new IllegalStateException( + "Failed to hibernate due to manager not being available", e); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); + Binder.restoreCallingIdentity(caller); + } + + // TODO: Support package level hibernation when package is hibernating for all users + } + } + + /** + * Populates {@link #mUserStates} with the users installed packages. The caller should hold + * {@link #mLock}. + * + * @param userId user id to add installed packages for + */ + private void addUserPackageStatesL(int userId) { + Map<String, UserPackageState> packages = new ArrayMap<>(); + List<PackageInfo> packageList; + try { + packageList = mIPackageManager.getInstalledPackages(MATCH_ALL, userId).getList(); + } catch (RemoteException e) { + throw new IllegalStateException("Package manager not available.", e); + } + + for (PackageInfo pkg : packageList) { + packages.put(pkg.packageName, new UserPackageState()); + } + mUserStates.put(userId, packages); + } + + private void onUserAdded(int userId) { + synchronized (mLock) { + addUserPackageStatesL(userId); + } + } + + private void onUserRemoved(int userId) { + synchronized (mLock) { + mUserStates.remove(userId); + } + } + + private void onPackageAdded(@NonNull String packageName, int userId) { + synchronized (mLock) { + mUserStates.get(userId).put(packageName, new UserPackageState()); + } + } + + private void onPackageRemoved(@NonNull String packageName, int userId) { + synchronized (mLock) { + mUserStates.get(userId).remove(packageName); + } + } + + /** + * Private helper method to get the real user id and enforce permission checks. + * + * @param userId user id to handle + * @param name name to use for exceptions + * @return real user id + */ + private int handleIncomingUser(int userId, @NonNull String name) { + int callingUid = Binder.getCallingUid(); + try { + return mIActivityManager.handleIncomingUser(Binder.getCallingPid(), callingUid, userId, + false /* allowAll */, true /* requireFull */, name, null); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + private final AppHibernationServiceStub mServiceStub = new AppHibernationServiceStub(this); + + static final class AppHibernationServiceStub extends IAppHibernationService.Stub { + final AppHibernationService mService; + + AppHibernationServiceStub(AppHibernationService service) { + mService = service; + } + + @Override + public boolean isHibernating(String packageName, int userId) { + return mService.isHibernating(packageName, userId); + } + + @Override + public void setHibernating(String packageName, int userId, boolean isHibernating) { + mService.setHibernating(packageName, userId, isHibernating); + } + + @Override + public void onShellCommand(@Nullable FileDescriptor in, @Nullable FileDescriptor out, + @Nullable FileDescriptor err, @NonNull String[] args, + @Nullable ShellCallback callback, @NonNull ResultReceiver resultReceiver) { + new AppHibernationShellCommand(mService).exec(this, in, out, err, args, callback, + resultReceiver); + } + } + + // Broadcast receiver for user and package add/removal events + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); + if (userId == UserHandle.USER_NULL) { + return; + } + + final String action = intent.getAction(); + if (ACTION_USER_ADDED.equals(action)) { + onUserAdded(userId); + } + if (ACTION_USER_REMOVED.equals(action)) { + onUserRemoved(userId); + } + if (ACTION_PACKAGE_ADDED.equals(action) || ACTION_PACKAGE_REMOVED.equals(action)) { + final String packageName = intent.getData().getSchemeSpecificPart(); + if (intent.getBooleanExtra(EXTRA_REPLACING, false)) { + // Package removal/add is part of an update, so no need to modify package state. + return; + } + + if (ACTION_PACKAGE_ADDED.equals(action)) { + onPackageAdded(packageName, userId); + } else if (ACTION_PACKAGE_REMOVED.equals(action)) { + onPackageRemoved(packageName, userId); + } + } + } + }; + + /** + * Whether app hibernation is enabled on this device. + * + * @return true if enabled, false otherwise + */ + public static boolean isAppHibernationEnabled() { + return DeviceConfig.getBoolean( + NAMESPACE_APP_HIBERNATION, + AppHibernationConstants.KEY_APP_HIBERNATION_ENABLED, + false /* defaultValue */); + } + + /** + * Data class that contains hibernation state info of a package for a user. + */ + private static final class UserPackageState { + public boolean hibernated; + // TODO: Track whether hibernation is exempted by the user + } +} diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java b/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java new file mode 100644 index 000000000000..869885e28958 --- /dev/null +++ b/services/core/java/com/android/server/apphibernation/AppHibernationShellCommand.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2021 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.apphibernation; + +import android.os.ShellCommand; +import android.os.UserHandle; +import android.text.TextUtils; + +import java.io.PrintWriter; + +/** + * Shell command implementation for {@link AppHibernationService}. + */ +final class AppHibernationShellCommand extends ShellCommand { + private static final String USER_OPT = "--user"; + private static final int SUCCESS = 0; + private static final int ERROR = -1; + private final AppHibernationService mService; + + AppHibernationShellCommand(AppHibernationService service) { + mService = service; + } + + @Override + public int onCommand(String cmd) { + if (cmd == null) { + return handleDefaultCommands(cmd); + } + switch (cmd) { + case "set-state": + return runSetState(); + case "get-state": + return runGetState(); + default: + return handleDefaultCommands(cmd); + } + } + + private int runSetState() { + int userId = parseUserOption(); + + String pkg = getNextArgRequired(); + if (pkg == null) { + getErrPrintWriter().println("Error: no package specified"); + return ERROR; + } + + String newStateRaw = getNextArgRequired(); + if (newStateRaw == null) { + getErrPrintWriter().println("Error: No state to set specified"); + return ERROR; + } + boolean newState = Boolean.parseBoolean(newStateRaw); + + mService.setHibernating(pkg, userId, newState); + return SUCCESS; + } + + private int runGetState() { + int userId = parseUserOption(); + + String pkg = getNextArgRequired(); + if (pkg == null) { + getErrPrintWriter().println("Error: No package specified"); + return ERROR; + } + boolean isHibernating = mService.isHibernating(pkg, userId); + final PrintWriter pw = getOutPrintWriter(); + pw.println(isHibernating); + return SUCCESS; + } + + private int parseUserOption() { + String option = getNextOption(); + if (TextUtils.equals(option, USER_OPT)) { + return UserHandle.parseUserArg(getNextArgRequired()); + } + return UserHandle.USER_CURRENT; + } + + @Override + public void onHelp() { + final PrintWriter pw = getOutPrintWriter(); + pw.println("App hibernation (app_hibernation) commands: "); + pw.println(" help"); + pw.println(" Print this help text."); + pw.println(""); + pw.println(" set-state [--user USER_ID] PACKAGE true|false"); + pw.println(" Sets the hibernation state of the package to value specified"); + pw.println(""); + pw.println(" get-state [--user USER_ID] PACKAGE"); + pw.println(" Gets the hibernation state of the package"); + pw.println(""); + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java index 01a620f7937c..d092e860e208 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java @@ -16,8 +16,11 @@ package com.android.server.biometrics.sensors.fingerprint; +import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.Context; import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; +import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.IUdfpsOverlayController; import android.os.RemoteException; import android.util.Slog; @@ -85,4 +88,33 @@ public class UdfpsHelper { Slog.e(TAG, "Remote exception when hiding the UDFPS overlay", e); } } + + public static void onEnrollmentProgress(int sensorId, int remaining, + @Nullable IUdfpsOverlayController udfpsOverlayController) { + if (udfpsOverlayController == null) { + return; + } + try { + udfpsOverlayController.onEnrollmentProgress(sensorId, remaining); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when sending onEnrollmentProgress", e); + } + } + + public static void onEnrollmentHelp(int sensorId, + @Nullable IUdfpsOverlayController udfpsOverlayController) { + if (udfpsOverlayController == null) { + return; + } + try { + udfpsOverlayController.onEnrollmentHelp(sensorId); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception when sending onEnrollmentHelp", e); + } + } + + public static boolean isValidAcquisitionMessage(@NonNull Context context, + int acquireInfo, int vendorCode) { + return FingerprintManager.getAcquiredString(context, acquireInfo, vendorCode) != null; + } } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java index 0864c1a69a6f..08cc464b4766 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java @@ -65,12 +65,23 @@ class FingerprintEnrollClient extends EnrollClient<ISession> implements Udfps { public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) { super.onEnrollResult(identifier, remaining); + UdfpsHelper.onEnrollmentProgress(getSensorId(), remaining, mUdfpsOverlayController); + if (remaining == 0) { UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController); } } @Override + public void onAcquired(int acquiredInfo, int vendorCode) { + super.onAcquired(acquiredInfo, vendorCode); + + if (UdfpsHelper.isValidAcquisitionMessage(getContext(), acquiredInfo, vendorCode)) { + UdfpsHelper.onEnrollmentHelp(getSensorId(), mUdfpsOverlayController); + } + } + + @Override public void onError(int errorCode, int vendorCode) { super.onError(errorCode, vendorCode); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java index acc575fb1973..a4a84019bae7 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java @@ -47,6 +47,7 @@ import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FrameworkStatsLog; import com.android.server.biometrics.SensorServiceStateProto; import com.android.server.biometrics.SensorStateProto; @@ -397,7 +398,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider }); } - private synchronized IBiometricsFingerprint getDaemon() { + @VisibleForTesting + synchronized IBiometricsFingerprint getDaemon() { if (mTestHalEnabled) { final TestHal testHal = new TestHal(); testHal.setNotify(mHalResultController); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java index 8493af13abd4..d927aa717fbc 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java @@ -107,12 +107,23 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) { super.onEnrollResult(identifier, remaining); + UdfpsHelper.onEnrollmentProgress(getSensorId(), remaining, mUdfpsOverlayController); + if (remaining == 0) { UdfpsHelper.hideUdfpsOverlay(getSensorId(), mUdfpsOverlayController); } } @Override + public void onAcquired(int acquiredInfo, int vendorCode) { + super.onAcquired(acquiredInfo, vendorCode); + + if (UdfpsHelper.isValidAcquisitionMessage(getContext(), acquiredInfo, vendorCode)) { + UdfpsHelper.onEnrollmentHelp(getSensorId(), mUdfpsOverlayController); + } + } + + @Override public void onError(int errorCode, int vendorCode) { super.onError(errorCode, vendorCode); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java index 11ffbb27128a..db7f4bcbec9d 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintUpdateActiveUserClient.java @@ -62,13 +62,7 @@ public class FingerprintUpdateActiveUserClient extends HalClientMonitor<IBiometr super.start(callback); if (mCurrentUserId == getTargetUserId()) { - Slog.d(TAG, "Already user: " + mCurrentUserId + ", refreshing authenticatorId"); - try { - mAuthenticatorIds.put(getTargetUserId(), mHasEnrolledBiometrics - ? getFreshDaemon().getAuthenticatorId() : 0L); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to refresh authenticatorId", e); - } + Slog.d(TAG, "Already user: " + mCurrentUserId + ", returning"); callback.onClientFinished(this, true /* success */); return; } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index fb1e8197ccff..8ce6746bc7cb 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -70,6 +70,7 @@ import android.net.NetworkRequest; import android.net.RouteInfo; import android.net.UidRange; import android.net.UidRangeParcel; +import android.net.VpnInfo; import android.net.VpnManager; import android.net.VpnService; import android.net.ipsec.ike.ChildSessionCallback; @@ -109,7 +110,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; -import com.android.internal.net.VpnInfo; import com.android.internal.net.VpnProfile; import com.android.server.DeviceIdleInternal; import com.android.server.LocalServices; @@ -1816,18 +1816,15 @@ public class Vpn { } /** - * This method should only be called by ConnectivityService because it doesn't - * have enough data to fill VpnInfo.primaryUnderlyingIface field. + * This method should not be called if underlying interfaces field is needed, because it doesn't + * have enough data to fill VpnInfo.underlyingIfaces field. */ public synchronized VpnInfo getVpnInfo() { if (!isRunningLocked()) { return null; } - VpnInfo info = new VpnInfo(); - info.ownerUid = mOwnerUID; - info.vpnIface = mInterface; - return info; + return new VpnInfo(mOwnerUID, mInterface, null); } public synchronized boolean appliesToUid(int uid) { diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java index d66bf6359426..69180643661f 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java @@ -303,6 +303,8 @@ public class HdmiCecConfig { return STORAGE_SHARED_PREFS; case HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY: return STORAGE_GLOBAL_SETTINGS; + case HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP: + return STORAGE_GLOBAL_SETTINGS; case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV: return STORAGE_SHARED_PREFS; case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU: @@ -338,6 +340,8 @@ public class HdmiCecConfig { return setting.getName(); case HdmiControlManager.CEC_SETTING_NAME_TV_WAKE_ON_ONE_TOUCH_PLAY: return Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED; + case HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP: + return Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED; case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_TV: return setting.getName(); case HdmiControlManager.CEC_SETTING_NAME_RC_PROFILE_SOURCE_HANDLES_ROOT_MENU: diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index ccce9dc43e6d..382f0f9d6329 100755 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -956,8 +956,6 @@ abstract class HdmiCecLocalDevice { } } - void setAutoDeviceOff(boolean enabled) {} - /** * Called when a hot-plug event issued. * diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java index b909b1639e1a..bf5bf8bae6fc 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java @@ -695,7 +695,6 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource { @ServiceThreadOnly void setArcStatus(boolean enabled) { - // TODO(shubang): add tests assertRunOnServiceThread(); HdmiLogger.debug("Set Arc Status[old:%b new:%b]", mArcEstablished, enabled); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java index e6cf18b8db3d..75b52f95d5bb 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java @@ -24,7 +24,6 @@ import android.hardware.tv.cec.V1_0.SendMessageResult; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.SystemProperties; -import android.provider.Settings.Global; import android.sysprop.HdmiProperties; import android.util.Slog; @@ -56,9 +55,6 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { // Lazily initialized - should call getWakeLock() to get the instance. private ActiveWakeLock mWakeLock; - // If true, turn off TV upon standby. False by default. - private boolean mAutoTvOff; - // Determines what action should be taken upon receiving Routing Control messages. @VisibleForTesting protected HdmiProperties.playback_device_action_on_routing_control_values @@ -68,12 +64,6 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { HdmiCecLocalDevicePlayback(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_PLAYBACK); - - mAutoTvOff = mService.readBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, false); - - // The option is false by default. Update settings db as well to have the right - // initial setting on UI. - mService.writeBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, mAutoTvOff); } @Override @@ -154,7 +144,10 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { // Invalidate the internal active source record when goes to standby mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS, "HdmiCecLocalDevicePlayback#onStandby()"); - if (initiatedByCec || !mAutoTvOff || !wasActiveSource) { + boolean mTvSendStandbyOnSleep = mService.getHdmiCecConfig().getIntValue( + HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP) + == HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED; + if (initiatedByCec || !mTvSendStandbyOnSleep || !wasActiveSource) { return; } switch (standbyAction) { @@ -201,13 +194,6 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { } @Override - @ServiceThreadOnly - void setAutoDeviceOff(boolean enabled) { - assertRunOnServiceThread(); - mAutoTvOff = enabled; - } - - @Override @CallSuper @ServiceThreadOnly @VisibleForTesting @@ -425,7 +411,6 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { protected void dump(final IndentingPrintWriter pw) { super.dump(pw); pw.println("isActiveSource(): " + isActiveSource()); - pw.println("mAutoTvOff:" + mAutoTvOff); } // Wrapper interface over PowerManager.WakeLock diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 5ef3738fc5b6..a3e18d161751 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -89,9 +89,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { @GuardedBy("mLock") private boolean mSystemAudioMute = false; - // If true, TV going to standby mode puts other devices also to standby. - private boolean mAutoDeviceOff; - private final HdmiCecStandbyModeHandler mStandbyHandler; // If true, do not do routing control/send active source for internal source. @@ -156,8 +153,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { HdmiCecLocalDeviceTv(HdmiControlService service) { super(service, HdmiDeviceInfo.DEVICE_TV); mPrevPortId = Constants.INVALID_PORT_ID; - mAutoDeviceOff = mService.readBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, - true); mSystemAudioControlFeatureEnabled = mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, true); mStandbyHandler = new HdmiCecStandbyModeHandler(service, this); @@ -1202,13 +1197,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } } - @Override - @ServiceThreadOnly - void setAutoDeviceOff(boolean enabled) { - assertRunOnServiceThread(); - mAutoDeviceOff = enabled; - } - @ServiceThreadOnly boolean getAutoWakeup() { assertRunOnServiceThread(); @@ -1286,7 +1274,11 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { if (!mService.isControlEnabled()) { return; } - if (!initiatedByCec && mAutoDeviceOff) { + boolean sendStandbyOnSleep = + mService.getHdmiCecConfig().getIntValue( + HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP) + == HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED; + if (!initiatedByCec && sendStandbyOnSleep) { mService.sendCecCommand(HdmiCecMessageBuilder.buildStandby( mAddress, Constants.ADDR_BROADCAST)); } @@ -1545,7 +1537,6 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { pw.println("mArcFeatureEnabled: " + mArcFeatureEnabled); pw.println("mSystemAudioMute: " + mSystemAudioMute); pw.println("mSystemAudioControlFeatureEnabled: " + mSystemAudioControlFeatureEnabled); - pw.println("mAutoDeviceOff: " + mAutoDeviceOff); pw.println("mSkipRoutingControl: " + mSkipRoutingControl); pw.println("mPrevPortId: " + mPrevPortId); } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 8febd4ff6c27..0ae1994bd368 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -661,7 +661,6 @@ public class HdmiControlService extends SystemService { ContentResolver resolver = getContext().getContentResolver(); String[] settings = new String[] { Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED, - Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, Global.MHL_INPUT_SWITCHING_ENABLED, Global.MHL_POWER_CHARGE_ENABLED, @@ -689,15 +688,6 @@ public class HdmiControlService extends SystemService { setHdmiCecVolumeControlEnabledInternal(getHdmiCecConfig().getIntValue( HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)); break; - case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED: - for (int type : mLocalDevices) { - HdmiCecLocalDevice localDevice = mHdmiCecNetwork.getLocalDevice(type); - if (localDevice != null) { - localDevice.setAutoDeviceOff(enabled); - } - } - // No need to propagate to HAL. - break; case Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED: if (isTvDeviceEnabled()) { tv().setSystemAudioControlFeatureEnabled(enabled); diff --git a/services/core/java/com/android/server/hdmi/cec_config.xml b/services/core/java/com/android/server/hdmi/cec_config.xml index a751fd73c542..191e725181ca 100644 --- a/services/core/java/com/android/server/hdmi/cec_config.xml +++ b/services/core/java/com/android/server/hdmi/cec_config.xml @@ -64,6 +64,15 @@ </allowed-values> <default-value int-value="1" /> </setting> + <setting name="tv_send_standby_on_sleep" + value-type="int" + user-configurable="true"> + <allowed-values> + <value int-value="0" /> + <value int-value="1" /> + </allowed-values> + <default-value int-value="1" /> + </setting> <setting name="rc_profile_tv" value-type="int" user-configurable="false"> diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index e9868fde3059..4faa7903c630 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -27,6 +27,7 @@ import static com.android.server.NetworkManagementSocketTagger.kernelToTag; import android.annotation.Nullable; import android.net.INetd; import android.net.NetworkStats; +import android.net.VpnInfo; import android.net.util.NetdService; import android.os.RemoteException; import android.os.StrictMode; @@ -34,7 +35,6 @@ import android.os.SystemClock; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 81a6641de8a4..4be7b483af16 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -105,6 +105,7 @@ import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; import android.net.Uri; +import android.net.VpnInfo; import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; @@ -143,7 +144,6 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FileRotator; diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java index 90ac69a97158..cf7460b306cd 100644 --- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java +++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerHw2Enforcer.java @@ -42,7 +42,7 @@ public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 { static final String TAG = "SoundTriggerHw2Enforcer"; final ISoundTriggerHw2 mUnderlying; - final Map<Integer, Boolean> mModelStates = new HashMap<>(); + Map<Integer, Boolean> mModelStates = new HashMap<>(); public SoundTriggerHw2Enforcer( ISoundTriggerHw2 underlying) { @@ -62,12 +62,12 @@ public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 { public int loadSoundModel(ISoundTriggerHw.SoundModel soundModel, Callback callback, int cookie) { try { + int handle = mUnderlying.loadSoundModel(soundModel, new CallbackEnforcer(callback), + cookie); synchronized (mModelStates) { - int handle = mUnderlying.loadSoundModel(soundModel, new CallbackEnforcer(callback), - cookie); mModelStates.put(handle, false); - return handle; } + return handle; } catch (RuntimeException e) { throw handleException(e); } @@ -77,13 +77,13 @@ public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 { public int loadPhraseSoundModel(ISoundTriggerHw.PhraseSoundModel soundModel, Callback callback, int cookie) { try { + int handle = mUnderlying.loadPhraseSoundModel(soundModel, + new CallbackEnforcer(callback), + cookie); synchronized (mModelStates) { - int handle = mUnderlying.loadPhraseSoundModel(soundModel, - new CallbackEnforcer(callback), - cookie); mModelStates.put(handle, false); - return handle; } + return handle; } catch (RuntimeException e) { throw handleException(e); } @@ -92,8 +92,8 @@ public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 { @Override public void unloadSoundModel(int modelHandle) { try { + mUnderlying.unloadSoundModel(modelHandle); synchronized (mModelStates) { - mUnderlying.unloadSoundModel(modelHandle); mModelStates.remove(modelHandle); } } catch (RuntimeException e) { @@ -104,8 +104,8 @@ public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 { @Override public void stopRecognition(int modelHandle) { try { + mUnderlying.stopRecognition(modelHandle); synchronized (mModelStates) { - mUnderlying.stopRecognition(modelHandle); mModelStates.replace(modelHandle, false); } } catch (RuntimeException e) { @@ -116,8 +116,8 @@ public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 { @Override public void stopAllRecognitions() { try { + mUnderlying.stopAllRecognitions(); synchronized (mModelStates) { - mUnderlying.stopAllRecognitions(); for (Map.Entry<Integer, Boolean> entry : mModelStates.entrySet()) { entry.setValue(false); } @@ -130,12 +130,14 @@ public class SoundTriggerHw2Enforcer implements ISoundTriggerHw2 { @Override public void startRecognition(int modelHandle, RecognitionConfig config, Callback callback, int cookie) { + // It is possible that an event will be sent before the HAL returns from the + // startRecognition call, thus it is important to set the state to active before the call. + synchronized (mModelStates) { + mModelStates.replace(modelHandle, true); + } try { - synchronized (mModelStates) { - mUnderlying.startRecognition(modelHandle, config, new CallbackEnforcer(callback), - cookie); - mModelStates.replace(modelHandle, true); - } + mUnderlying.startRecognition(modelHandle, config, new CallbackEnforcer(callback), + cookie); } catch (RuntimeException e) { throw handleException(e); } diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java index e1feb5aab869..6427ae2dc13c 100644 --- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -24,6 +24,9 @@ import android.net.NetworkCapabilities; import android.os.Handler; import android.os.ParcelUuid; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.annotations.VisibleForTesting.Visibility; + import java.util.Objects; /** @@ -72,7 +75,8 @@ public class UnderlyingNetworkTracker extends Handler { @NonNull public final LinkProperties linkProperties; public final boolean blocked; - private UnderlyingNetworkRecord( + @VisibleForTesting(visibility = Visibility.PRIVATE) + UnderlyingNetworkRecord( @NonNull Network network, @NonNull NetworkCapabilities networkCapabilities, @NonNull LinkProperties linkProperties, diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 4e0c0c54923b..0fa97a26e67c 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -24,7 +24,6 @@ import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; import android.annotation.Nullable; -import android.net.ConnectivityManager; import android.net.InetAddresses; import android.net.IpPrefix; import android.net.IpSecManager; @@ -36,8 +35,6 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkAgent; import android.net.NetworkCapabilities; -import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; import android.net.RouteInfo; import android.net.annotations.PolicyDirection; import android.net.ipsec.ike.ChildSessionCallback; @@ -54,7 +51,6 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.Message; import android.os.ParcelUuid; -import android.telephony.TelephonyManager; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -360,11 +356,25 @@ public class VcnGatewayConnection extends StateMachine { */ private static final int EVENT_TEARDOWN_TIMEOUT_EXPIRED = 8; - @NonNull private final DisconnectedState mDisconnectedState = new DisconnectedState(); - @NonNull private final DisconnectingState mDisconnectingState = new DisconnectingState(); - @NonNull private final ConnectingState mConnectingState = new ConnectingState(); - @NonNull private final ConnectedState mConnectedState = new ConnectedState(); - @NonNull private final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState(); + @VisibleForTesting(visibility = Visibility.PRIVATE) + @NonNull + final DisconnectedState mDisconnectedState = new DisconnectedState(); + + @VisibleForTesting(visibility = Visibility.PRIVATE) + @NonNull + final DisconnectingState mDisconnectingState = new DisconnectingState(); + + @VisibleForTesting(visibility = Visibility.PRIVATE) + @NonNull + final ConnectingState mConnectingState = new ConnectingState(); + + @VisibleForTesting(visibility = Visibility.PRIVATE) + @NonNull + final ConnectedState mConnectedState = new ConnectedState(); + + @VisibleForTesting(visibility = Visibility.PRIVATE) + @NonNull + final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState(); @NonNull private final VcnContext mVcnContext; @NonNull private final ParcelUuid mSubscriptionGroup; @@ -455,7 +465,8 @@ public class VcnGatewayConnection extends StateMachine { this(vcnContext, subscriptionGroup, connectionConfig, new Dependencies()); } - private VcnGatewayConnection( + @VisibleForTesting(visibility = Visibility.PRIVATE) + VcnGatewayConnection( @NonNull VcnContext vcnContext, @NonNull ParcelUuid subscriptionGroup, @NonNull VcnGatewayConnectionConfig connectionConfig, @@ -508,7 +519,6 @@ public class VcnGatewayConnection extends StateMachine { EVENT_DISCONNECT_REQUESTED, TOKEN_ALL, new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN)); - quit(); // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this // is also called asynchronously when a NetworkAgent becomes unwanted @@ -654,7 +664,7 @@ public class VcnGatewayConnection extends StateMachine { protected void teardownNetwork() { if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkInfo(buildNetworkInfo(false /* isConnected */)); + mNetworkAgent.unregister(); mNetworkAgent = null; } } @@ -667,6 +677,8 @@ public class VcnGatewayConnection extends StateMachine { protected void handleDisconnectRequested(String msg) { Slog.v(TAG, "Tearing down. Cause: " + msg); + mIsRunning = false; + teardownNetwork(); teardownIke(); @@ -697,7 +709,37 @@ public class VcnGatewayConnection extends StateMachine { */ private class DisconnectedState extends BaseState { @Override - protected void processStateMsg(Message msg) {} + protected void enterState() { + if (!mIsRunning) { + quitNow(); // Ignore all queued events; cleanup is complete. + } + + if (mIkeSession != null || mNetworkAgent != null) { + Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState"); + } + } + + @Override + protected void processStateMsg(Message msg) { + switch (msg.what) { + case EVENT_UNDERLYING_NETWORK_CHANGED: + // First network found; start tunnel + mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying; + + if (mUnderlying != null) { + transitionTo(mConnectingState); + } + break; + case EVENT_DISCONNECT_REQUESTED: + mIsRunning = false; + + quitNow(); + break; + default: + logUnhandledMessage(msg); + break; + } + } } private abstract class ActiveBaseState extends BaseState { @@ -769,20 +811,6 @@ public class VcnGatewayConnection extends StateMachine { protected void processStateMsg(Message msg) {} } - // TODO: Remove this when migrating to new NetworkAgent API - private static NetworkInfo buildNetworkInfo(boolean isConnected) { - NetworkInfo info = - new NetworkInfo( - ConnectivityManager.TYPE_MOBILE, - TelephonyManager.NETWORK_TYPE_UNKNOWN, - "MOBILE", - "VCN"); - info.setDetailedState( - isConnected ? DetailedState.CONNECTED : DetailedState.DISCONNECTED, null, null); - - return info; - } - @VisibleForTesting(visibility = Visibility.PRIVATE) static NetworkCapabilities buildNetworkCapabilities( @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) { @@ -893,7 +921,32 @@ public class VcnGatewayConnection extends StateMachine { } } - /** External dependencies used by VcnGatewayConnection, for injection in tests. */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + UnderlyingNetworkTrackerCallback getUnderlyingNetworkTrackerCallback() { + return mUnderlyingNetworkTrackerCallback; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + UnderlyingNetworkRecord getUnderlyingNetwork() { + return mUnderlying; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + void setUnderlyingNetwork(@Nullable UnderlyingNetworkRecord record) { + mUnderlying = record; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + boolean isRunning() { + return mIsRunning; + } + + @VisibleForTesting(visibility = Visibility.PRIVATE) + void setIsRunning(boolean isRunning) { + mIsRunning = isRunning; + } + + /** External dependencies used by VcnGatewayConnection, for injection in tests */ @VisibleForTesting(visibility = Visibility.PRIVATE) public static class Dependencies { /** Builds a new UnderlyingNetworkTracker. */ diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index ae20a725b765..72574786c46b 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -37,15 +37,11 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Binder; -import android.os.Handler; import android.os.IBinder; -import android.os.Looper; -import android.os.Message; import android.os.UserHandle; import android.provider.Settings; import android.util.Slog; import android.util.SparseArray; -import android.util.proto.ProtoOutputStream; import android.view.RemoteAnimationAdapter; import com.android.internal.annotations.VisibleForTesting; @@ -55,10 +51,8 @@ import com.android.server.am.PendingIntentRecord; import com.android.server.uri.NeededUriGrants; import com.android.server.wm.ActivityStarter.DefaultFactory; import com.android.server.wm.ActivityStarter.Factory; -import com.android.server.wm.ActivityTaskSupervisor.PendingActivityLaunch; import java.io.PrintWriter; -import java.util.ArrayList; import java.util.List; /** @@ -87,35 +81,12 @@ public class ActivityStartController { /** The result of the last home activity we attempted to start. */ private int mLastHomeActivityStartResult; - /** A list of activities that are waiting to launch. */ - private final ArrayList<ActivityTaskSupervisor.PendingActivityLaunch> - mPendingActivityLaunches = new ArrayList<>(); - private final Factory mFactory; - private final Handler mHandler; - private final PendingRemoteAnimationRegistry mPendingRemoteAnimationRegistry; boolean mCheckedForSetup = false; - private final class StartHandler extends Handler { - public StartHandler(Looper looper) { - super(looper, null, true); - } - - @Override - public void handleMessage(Message msg) { - switch(msg.what) { - case DO_PENDING_ACTIVITY_LAUNCHES_MSG: - synchronized (mService.mGlobalLock) { - doPendingActivityLaunches(true); - } - break; - } - } - } - /** * TODO(b/64750076): Capture information necessary for dump and * {@link #postStartActivityProcessingForLastStarter} rather than keeping the entire object @@ -134,7 +105,6 @@ public class ActivityStartController { Factory factory) { mService = service; mSupervisor = supervisor; - mHandler = new StartHandler(mService.mH.getLooper()); mFactory = factory; mFactory.setController(this); mPendingRemoteAnimationRegistry = new PendingRemoteAnimationRegistry(service.mGlobalLock, @@ -514,45 +484,6 @@ public class ActivityStartController { return START_SUCCESS; } - void schedulePendingActivityLaunches(long delayMs) { - mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG); - Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG); - mHandler.sendMessageDelayed(msg, delayMs); - } - - void doPendingActivityLaunches(boolean doResume) { - while (!mPendingActivityLaunches.isEmpty()) { - final PendingActivityLaunch pal = mPendingActivityLaunches.remove(0); - final boolean resume = doResume && mPendingActivityLaunches.isEmpty(); - final ActivityStarter starter = obtainStarter(null /* intent */, - "pendingActivityLaunch"); - try { - starter.startResolvedActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, - resume, pal.r.getOptions(), null, pal.intentGrants); - } catch (Exception e) { - Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e); - pal.sendErrorResult(e.getMessage()); - } - } - } - - void addPendingActivityLaunch(PendingActivityLaunch launch) { - mPendingActivityLaunches.add(launch); - } - - boolean clearPendingActivityLaunches(String packageName) { - final int pendingLaunches = mPendingActivityLaunches.size(); - - for (int palNdx = pendingLaunches - 1; palNdx >= 0; --palNdx) { - final PendingActivityLaunch pal = mPendingActivityLaunches.get(palNdx); - final ActivityRecord r = pal.r; - if (r != null && r.packageName.equals(packageName)) { - mPendingActivityLaunches.remove(palNdx); - } - } - return mPendingActivityLaunches.size() < pendingLaunches; - } - void registerRemoteAnimationForNextActivityStart(String packageName, RemoteAnimationAdapter adapter) { mPendingRemoteAnimationRegistry.addPendingAnimation(packageName, adapter); @@ -609,10 +540,4 @@ public class ActivityStartController { pw.println("(nothing)"); } } - - public void dumpDebug(ProtoOutputStream proto, long fieldId) { - for (PendingActivityLaunch activity: mPendingActivityLaunches) { - activity.r.writeIdentifierToProto(proto, fieldId); - } - } } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 4fa4a677a71a..c6ed16ce1f4d 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -122,7 +122,6 @@ import com.android.server.power.ShutdownCheckPoints; import com.android.server.statusbar.StatusBarManagerInternal; import com.android.server.uri.NeededUriGrants; import com.android.server.wm.ActivityMetricsLogger.LaunchingState; -import com.android.server.wm.ActivityTaskSupervisor.PendingActivityLaunch; import com.android.server.wm.LaunchParamsController.LaunchParams; import java.io.PrintWriter; @@ -1171,42 +1170,19 @@ class ActivityStarter { r.appTimeTracker = sourceRecord.appTimeTracker; } - final Task rootTask = mRootWindowContainer.getTopDisplayFocusedRootTask(); - - // If we are starting an activity that is not from the same uid as the currently resumed - // one, check whether app switches are allowed. - if (voiceSession == null && rootTask != null && (rootTask.getResumedActivity() == null - || rootTask.getResumedActivity().info.applicationInfo.uid != realCallingUid)) { - if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, - realCallingPid, realCallingUid, "Activity start")) { - if (!(restrictedBgActivity && handleBackgroundActivityAbort(r))) { - mController.addPendingActivityLaunch(new PendingActivityLaunch(r, - sourceRecord, startFlags, rootTask, callerApp, intentGrants)); - } - ActivityOptions.abort(checkedOptions); - return ActivityManager.START_SWITCHES_CANCELED; - } - } - - if (mService.getBalAppSwitchesProtectionEnabled()) { - // Only allow app switching to be resumed if activity is not a restricted background - // activity and target app is not home process, otherwise any background activity - // started in background task can stop home button protection mode. - // As the targeted app is not a home process and we don't need to wait for the 2nd - // activity to be started to resume app switching, we can just enable app switching - // directly. - WindowProcessController homeProcess = mService.mHomeProcess; - boolean isHomeProcess = homeProcess != null - && aInfo.applicationInfo.uid == homeProcess.mUid; - if (!restrictedBgActivity && !isHomeProcess) { - mService.resumeAppSwitches(); - } - } else { - mService.onStartActivitySetDidAppSwitch(); + // Only allow app switching to be resumed if activity is not a restricted background + // activity and target app is not home process, otherwise any background activity + // started in background task can stop home button protection mode. + // As the targeted app is not a home process and we don't need to wait for the 2nd + // activity to be started to resume app switching, we can just enable app switching + // directly. + WindowProcessController homeProcess = mService.mHomeProcess; + boolean isHomeProcess = homeProcess != null + && aInfo.applicationInfo.uid == homeProcess.mUid; + if (!restrictedBgActivity && !isHomeProcess) { + mService.resumeAppSwitches(); } - mController.doPendingActivityLaunches(false); - mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession, request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask, restrictedBgActivity, intentGrants); @@ -1286,8 +1262,6 @@ class ActivityStarter { return false; } - // App switching will be allowed if BAL app switching flag is not enabled, or if - // its app switching rule allows it. // This is used to block background activity launch even if the app is still // visible to user after user clicking home button. final boolean appSwitchAllowed = mService.getBalAppSwitchesAllowed(); @@ -1438,7 +1412,6 @@ class ActivityStarter { Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage + "; callingUid: " + callingUid + "; appSwitchAllowed: " + appSwitchAllowed - + "; balAppSwitchEnabled: " + mService.getBalAppSwitchesProtectionEnabled() + "; isCallingUidForeground: " + isCallingUidForeground + "; callingUidHasAnyVisibleWindow: " + callingUidHasAnyVisibleWindow + "; callingUidProcState: " + DebugUtils.valueToString(ActivityManager.class, diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 80add64bf4c3..56105737bb82 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -202,7 +202,6 @@ import android.os.UserManager; import android.os.WorkSource; import android.os.storage.IStorageManager; import android.os.storage.StorageManager; -import android.provider.DeviceConfig; import android.provider.Settings; import android.service.dreams.DreamActivity; import android.service.voice.IVoiceInteractionSession; @@ -324,12 +323,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** This activity is being relaunched due to a free-resize operation. */ public static final int RELAUNCH_REASON_FREE_RESIZE = 2; - /** - * Apps are blocked from starting activities in the foreground after the user presses home. - */ - public static final String BLOCK_ACTIVITY_STARTS_AFTER_HOME_FLAG = - "am_block_activity_starts_after_home"; - Context mContext; /** @@ -386,7 +379,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { volatile WindowProcessController mHeavyWeightProcess; boolean mHasHeavyWeightFeature; boolean mHasLeanbackFeature; - boolean mBlockActivityAfterHomeEnabled; /** The process of the top most activity. */ volatile WindowProcessController mTopApp; /** @@ -490,20 +482,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { /** Temporary to avoid allocations. */ final StringBuilder mStringBuilder = new StringBuilder(256); - // Amount of time after a call to stopAppSwitches() during which we will - // prevent further untrusted switches from happening. - private static final long APP_SWITCH_DELAY_TIME = 5 * 1000; - /** - * The time at which we will allow normal application switches again, - * after a call to {@link #stopAppSwitches()}. + * Whether normal application switches are allowed; a call to {@link #stopAppSwitches() + * disables this. */ - private long mAppSwitchesAllowedTime; - /** - * This is set to true after the first switch after mAppSwitchesAllowedTime - * is set; any switches after that will clear the time. - */ - private boolean mDidAppSwitch; + private boolean mAppSwitchesAllowed = true; /** * Last stop app switches time, apps finished before this time cannot start background activity @@ -749,9 +732,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { mRecentTasks.onSystemReadyLocked(); mTaskSupervisor.onSystemReady(); mActivityClientController.onSystemReady(); - mBlockActivityAfterHomeEnabled = DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, - BLOCK_ACTIVITY_STARTS_AFTER_HOME_FLAG, true); } } @@ -1146,7 +1126,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (topFocusedRootTask != null && topFocusedRootTask.getResumedActivity() != null && topFocusedRootTask.getResumedActivity().info.applicationInfo.uid == Binder.getCallingUid()) { - mAppSwitchesAllowedTime = 0; + mAppSwitchesAllowed = true; } } return pir.sendInner(0, fillInIntent, resolvedType, allowlistToken, null, null, @@ -2002,10 +1982,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); assertPackageMatchesCallingUid(callingPackage); - if (!checkAppSwitchAllowedLocked(callingPid, callingUid, -1, -1, "Task to front")) { - SafeActivityOptions.abort(options); - return; - } + final long origId = Binder.clearCallingIdentity(); WindowProcessController callerApp = null; if (appThread != null) { @@ -2086,76 +2063,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } /** - * Return true if app switch protection will be handled by background activity launch logic. - */ - boolean getBalAppSwitchesProtectionEnabled() { - return mBlockActivityAfterHomeEnabled; - } - - /** * Return true if app switching is allowed. */ boolean getBalAppSwitchesAllowed() { - if (getBalAppSwitchesProtectionEnabled()) { - // Apps no longer able to start BAL again until app switching is resumed. - return mAppSwitchesAllowedTime == 0; - } else { - // Legacy behavior, BAL logic won't block app switching. - return true; - } - } - - boolean checkAppSwitchAllowedLocked(int sourcePid, int sourceUid, - int callingPid, int callingUid, String name) { - - // Background activity launch logic replaces app switching protection, so allow - // apps to start activity here now. - if (getBalAppSwitchesProtectionEnabled()) { - return true; - } - - if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) { - return true; - } - - if (getRecentTasks().isCallerRecents(sourceUid)) { - return true; - } - - int perm = checkComponentPermission(STOP_APP_SWITCHES, sourcePid, sourceUid, -1, true); - if (perm == PackageManager.PERMISSION_GRANTED) { - return true; - } - if (checkAllowAppSwitchUid(sourceUid)) { - return true; - } - - // If the actual IPC caller is different from the logical source, then - // also see if they are allowed to control app switches. - if (callingUid != -1 && callingUid != sourceUid) { - perm = checkComponentPermission(STOP_APP_SWITCHES, callingPid, callingUid, -1, true); - if (perm == PackageManager.PERMISSION_GRANTED) { - return true; - } - if (checkAllowAppSwitchUid(callingUid)) { - return true; - } - } - - Slog.w(TAG, name + " request from " + sourceUid + " stopped"); - return false; - } - - private boolean checkAllowAppSwitchUid(int uid) { - ArrayMap<String, Integer> types = mAllowAppSwitchUids.get(UserHandle.getUserId(uid)); - if (types != null) { - for (int i = types.size() - 1; i >= 0; i--) { - if (types.valueAt(i).intValue() == uid) { - return true; - } - } - } - return false; + return mAppSwitchesAllowed; } @Override @@ -3663,13 +3574,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public void stopAppSwitches() { enforceCallerIsRecentsOrHasPermission(STOP_APP_SWITCHES, "stopAppSwitches"); synchronized (mGlobalLock) { - mAppSwitchesAllowedTime = SystemClock.uptimeMillis() + APP_SWITCH_DELAY_TIME; + mAppSwitchesAllowed = false; mLastStopAppSwitchesTime = SystemClock.uptimeMillis(); - mDidAppSwitch = false; - // If BAL app switching enabled, app switches are blocked not delayed. - if (!getBalAppSwitchesProtectionEnabled()) { - getActivityStartController().schedulePendingActivityLaunches(APP_SWITCH_DELAY_TIME); - } } } @@ -3677,10 +3583,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { public void resumeAppSwitches() { enforceCallerIsRecentsOrHasPermission(STOP_APP_SWITCHES, "resumeAppSwitches"); synchronized (mGlobalLock) { - // Note that we don't execute any pending app switches... we will - // let those wait until either the timeout, or the next start - // activity request. - mAppSwitchesAllowedTime = 0; + mAppSwitchesAllowed = true; } } @@ -3688,19 +3591,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return mLastStopAppSwitchesTime; } - void onStartActivitySetDidAppSwitch() { - if (mDidAppSwitch) { - // This is the second allowed switch since we stopped switches, so now just generally - // allow switches. Use case: - // - user presses home (switches disabled, switch to home, mDidAppSwitch now true); - // - user taps a home icon (coming from home so allowed, we hit here and now allow - // anyone to switch again). - mAppSwitchesAllowedTime = 0; - } else { - mDidAppSwitch = true; - } - } - /** @return whether the system should disable UI modes incompatible with VR mode. */ boolean shouldDisableNonVrUiLocked() { return mVrController.shouldDisableNonVrUiLocked(); @@ -5822,15 +5712,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { int userId) { synchronized (mGlobalLock) { - boolean didSomething = - getActivityStartController().clearPendingActivityLaunches(packageName); - didSomething |= mRootWindowContainer.finishDisabledPackageActivities(packageName, + return mRootWindowContainer.finishDisabledPackageActivities(packageName, null /* filterByClasses */, doit, evenPersistent, userId, // Only remove the activities without process because the activities with // attached process will be removed when handling process died with // WindowProcessController#isRemoved == true. true /* onlyRemoveNoProcess */); - return didSomething; } } diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 0ad392bbbf8b..de436437769a 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -142,7 +142,6 @@ import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.am.ActivityManagerService; import com.android.server.am.UserState; -import com.android.server.uri.NeededUriGrants; import com.android.server.wm.ActivityMetricsLogger.LaunchingState; import java.io.FileDescriptor; @@ -376,41 +375,6 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { private boolean mInitialized; - /** - * Description of a request to start a new activity, which has been held - * due to app switches being disabled. - */ - static class PendingActivityLaunch { - final ActivityRecord r; - final ActivityRecord sourceRecord; - final int startFlags; - final Task rootTask; - final WindowProcessController callerApp; - final NeededUriGrants intentGrants; - - PendingActivityLaunch(ActivityRecord r, ActivityRecord sourceRecord, - int startFlags, Task rootTask, WindowProcessController callerApp, - NeededUriGrants intentGrants) { - this.r = r; - this.sourceRecord = sourceRecord; - this.startFlags = startFlags; - this.rootTask = rootTask; - this.callerApp = callerApp; - this.intentGrants = intentGrants; - } - - void sendErrorResult(String message) { - try { - if (callerApp != null && callerApp.hasThread()) { - callerApp.getThread().scheduleCrash(message); - } - } catch (RemoteException e) { - Slog.e(TAG, "Exception scheduling crash of failed " - + "activity launcher sourceRecord=" + sourceRecord, e); - } - } - } - public ActivityTaskSupervisor(ActivityTaskManagerService service, Looper looper) { mService = service; mLooper = looper; diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java index e6b758585b20..7f0adcacc951 100644 --- a/services/core/java/com/android/server/wm/AppTaskImpl.java +++ b/services/core/java/com/android/server/wm/AppTaskImpl.java @@ -101,10 +101,6 @@ class AppTaskImpl extends IAppTask.Stub { final long origId = Binder.clearCallingIdentity(); try { synchronized (mService.mGlobalLock) { - if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid, -1, -1, - "Move to front")) { - return; - } WindowProcessController callerApp = null; if (appThread != null) { callerApp = mService.getProcessController(appThread); diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index ce4e5ec675e4..bbf6c7616d46 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -68,7 +68,6 @@ import static com.android.server.wm.ActivityTaskSupervisor.printThisActivity; import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; import static com.android.server.wm.RootWindowContainerProto.IS_HOME_RECENTS_COMPONENT; import static com.android.server.wm.RootWindowContainerProto.KEYGUARD_CONTROLLER; -import static com.android.server.wm.RootWindowContainerProto.PENDING_ACTIVITIES; import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER; import static com.android.server.wm.Task.ActivityState.FINISHING; import static com.android.server.wm.Task.ActivityState.PAUSED; @@ -1289,7 +1288,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent> mTaskSupervisor.getKeyguardController().dumpDebug(proto, KEYGUARD_CONTROLLER); proto.write(IS_HOME_RECENTS_COMPONENT, mTaskSupervisor.mRecentTasks.isRecentsComponentHomeActivity(mCurrentUser)); - mService.getActivityStartController().dumpDebug(proto, PENDING_ACTIVITIES); proto.end(token); } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index ad2bc65c0d01..12595af1db7f 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -103,6 +103,7 @@ import com.android.internal.util.FrameworkStatsLog; import com.android.internal.widget.ILockSettings; import com.android.server.am.ActivityManagerService; import com.android.server.appbinding.AppBindingService; +import com.android.server.apphibernation.AppHibernationService; import com.android.server.attention.AttentionManagerService; import com.android.server.audio.AudioService; import com.android.server.biometrics.AuthService; @@ -236,6 +237,8 @@ public final class SystemServer implements Dumpable { "com.android.server.appwidget.AppWidgetService"; private static final String VOICE_RECOGNITION_MANAGER_SERVICE_CLASS = "com.android.server.voiceinteraction.VoiceInteractionManagerService"; + private static final String APP_HIBERNATION_SERVICE_CLASS = + "com.android.server.apphibernation.AppHibernationService"; private static final String PRINT_MANAGER_SERVICE_CLASS = "com.android.server.print.PrintManagerService"; private static final String COMPANION_DEVICE_MANAGER_SERVICE_CLASS = @@ -495,7 +498,7 @@ public final class SystemServer implements Dumpable { } try { - Thread.sleep(checkInterval); + Thread.sleep(checkInterval * 1000); } catch (InterruptedException ex) { continue; } @@ -2047,6 +2050,12 @@ public final class SystemServer implements Dumpable { mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS); t.traceEnd(); + if (AppHibernationService.isAppHibernationEnabled()) { + t.traceBegin("StartAppHibernationService"); + mSystemServiceManager.startService(APP_HIBERNATION_SERVICE_CLASS); + t.traceEnd(); + } + if (GestureLauncherService.isGestureLauncherEnabled(context.getResources())) { t.traceBegin("StartGestureLauncher"); mSystemServiceManager.startService(GestureLauncherService.class); diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java new file mode 100644 index 000000000000..d0370b6c25e9 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2021 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.apphibernation; + +import static org.junit.Assert.assertTrue; +import static org.mockito.AdditionalAnswers.returnsArgAt; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; +import static org.mockito.internal.verification.VerificationModeFactory.times; + +import android.app.IActivityManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.IPackageManager; +import android.content.pm.PackageInfo; +import android.content.pm.ParceledListSlice; +import android.content.pm.UserInfo; +import android.net.Uri; +import android.os.RemoteException; +import android.os.UserManager; + +import androidx.test.filters.SmallTest; + +import com.android.server.SystemService; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tests for {@link com.android.server.apphibernation.AppHibernationService} + */ +@SmallTest +public final class AppHibernationServiceTest { + private static final String PACKAGE_SCHEME = "package"; + private static final String PACKAGE_NAME_1 = "package1"; + private static final String PACKAGE_NAME_2 = "package2"; + private static final int USER_ID_1 = 1; + private static final int USER_ID_2 = 2; + + private AppHibernationService mAppHibernationService; + private BroadcastReceiver mBroadcastReceiver; + @Mock + private Context mContext; + @Mock + private IPackageManager mIPackageManager; + @Mock + private IActivityManager mIActivityManager; + @Mock + private UserManager mUserManager; + @Captor + private ArgumentCaptor<BroadcastReceiver> mReceiverCaptor; + + @Before + public void setUp() throws RemoteException { + MockitoAnnotations.initMocks(this); + doReturn(mContext).when(mContext).createContextAsUser(any(), anyInt()); + + mAppHibernationService = new AppHibernationService(mContext, mIPackageManager, + mIActivityManager, mUserManager); + + verify(mContext, times(2)).registerReceiver(mReceiverCaptor.capture(), any()); + mBroadcastReceiver = mReceiverCaptor.getValue(); + + List<UserInfo> userList = new ArrayList<>(); + userList.add(new UserInfo(USER_ID_1, "user 1", 0 /* flags */)); + doReturn(userList).when(mUserManager).getUsers(); + + List<PackageInfo> userPackages = new ArrayList<>(); + userPackages.add(makePackageInfo(PACKAGE_NAME_1)); + + doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager) + .getInstalledPackages(anyInt(), eq(USER_ID_1)); + + doAnswer(returnsArgAt(2)).when(mIActivityManager).handleIncomingUser(anyInt(), anyInt(), + anyInt(), anyBoolean(), anyBoolean(), any(), any()); + + mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); + } + + @Test + public void testSetHibernating_packageIsHibernating() { + // WHEN we hibernate a package for a user + mAppHibernationService.setHibernating(PACKAGE_NAME_1, USER_ID_1, true); + + // THEN the package is marked hibernating for the user + assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_1, USER_ID_1)); + } + + @Test + public void testSetHibernating_newPackageAdded_packageIsHibernating() { + // WHEN a new package is added and it is hibernated + Intent intent = new Intent(Intent.ACTION_PACKAGE_ADDED, + Uri.fromParts(PACKAGE_SCHEME, PACKAGE_NAME_2, null /* fragment */)); + intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_1); + mBroadcastReceiver.onReceive(mContext, intent); + + mAppHibernationService.setHibernating(PACKAGE_NAME_2, USER_ID_1, true); + + // THEN the new package is hibernated + assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_2, USER_ID_1)); + } + + @Test + public void testSetHibernating_newUserAdded_packageIsHibernating() throws RemoteException { + // WHEN a new user is added and a package from the user is hibernated + List<PackageInfo> userPackages = new ArrayList<>(); + userPackages.add(makePackageInfo(PACKAGE_NAME_1)); + doReturn(new ParceledListSlice<>(userPackages)).when(mIPackageManager) + .getInstalledPackages(anyInt(), eq(USER_ID_2)); + Intent intent = new Intent(Intent.ACTION_USER_ADDED); + intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_2); + mBroadcastReceiver.onReceive(mContext, intent); + + mAppHibernationService.setHibernating(PACKAGE_NAME_1, USER_ID_2, true); + + // THEN the new user's package is hibernated + assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_1, USER_ID_2)); + } + + @Test + public void testIsHibernating_packageReplaced_stillReturnsHibernating() { + // GIVEN a package is currently hibernated + mAppHibernationService.setHibernating(PACKAGE_NAME_1, USER_ID_1, true); + + // WHEN the package is removed but marked as replacing + Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED, + Uri.fromParts(PACKAGE_SCHEME, PACKAGE_NAME_2, null /* fragment */)); + intent.putExtra(Intent.EXTRA_USER_HANDLE, USER_ID_1); + intent.putExtra(Intent.EXTRA_REPLACING, true); + mBroadcastReceiver.onReceive(mContext, intent); + + // THEN the package is still hibernating + assertTrue(mAppHibernationService.isHibernating(PACKAGE_NAME_1, USER_ID_1)); + } + + private static PackageInfo makePackageInfo(String packageName) { + PackageInfo pkg = new PackageInfo(); + pkg.packageName = packageName; + return pkg; + } +} diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java index 61cc8e6e8ea3..904ade82a51f 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java @@ -19,17 +19,20 @@ package com.android.server.biometrics.sensors.fingerprint.hidl; import static junit.framework.Assert.assertEquals; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; import android.hardware.biometrics.BiometricManager; +import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint; import android.os.Handler; import android.os.Looper; import android.os.UserManager; import android.platform.test.annotations.Presubmit; +import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -80,7 +83,7 @@ public class Fingerprint21Test { .thenReturn(5); mLockoutResetDispatcher = new LockoutResetDispatcher(mContext); - mFingerprint21 = new Fingerprint21(mContext, mScheduler, + mFingerprint21 = new TestableFingerprint21(mContext, mScheduler, new Handler(Looper.getMainLooper()), SENSOR_ID, BiometricManager.Authenticators.BIOMETRIC_WEAK, mLockoutResetDispatcher, mHalResultController); @@ -100,4 +103,21 @@ public class Fingerprint21Test { waitForIdle(); verify(mScheduler).reset(); } + + private static class TestableFingerprint21 extends Fingerprint21 { + + TestableFingerprint21(@NonNull Context context, + @NonNull BiometricScheduler scheduler, + @NonNull Handler handler, int sensorId, int strength, + @NonNull LockoutResetDispatcher lockoutResetDispatcher, + @NonNull HalResultController controller) { + super(context, scheduler, handler, sensorId, strength, lockoutResetDispatcher, + controller); + } + + @Override + synchronized IBiometricsFingerprint getDaemon() { + return mock(IBiometricsFingerprint.class); + } + } } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java index a408d4ca02cf..137bd88b1489 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java @@ -113,6 +113,15 @@ final class FakeHdmiCecConfig extends HdmiCecConfig { + " </allowed-values>" + " <default-value int-value=\"1\" />" + " </setting>" + + " <setting name=\"tv_send_standby_on_sleep\"" + + " value-type=\"int\"" + + " user-configurable=\"true\">" + + " <allowed-values>" + + " <value int-value=\"0\" />" + + " <value int-value=\"1\" />" + + " </allowed-values>" + + " <default-value int-value=\"1\" />" + + " </setting>" + " <setting name=\"rc_profile_tv\"" + " value-type=\"int\"" + " user-configurable=\"false\">" diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java index 95a0a7439904..eedbc958dcd5 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java @@ -596,6 +596,15 @@ public class HdmiCecLocalDeviceAudioSystemTest { } @Test + public void setArcStatus() { + mHdmiCecLocalDeviceAudioSystem.setArcStatus(true); + assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isTrue(); + + mHdmiCecLocalDeviceAudioSystem.setArcStatus(false); + assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse(); + } + + @Test @Ignore("b/151150320") public void handleSystemAudioModeRequest_fromNonTV_tVNotSupport() { HdmiCecMessage message = diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java index 882d2f5f1529..e6b56ca3418f 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java @@ -35,7 +35,6 @@ import android.os.Looper; import android.os.PowerManager; import android.os.test.TestLooper; import android.platform.test.annotations.Presubmit; -import android.provider.Settings.Global; import android.sysprop.HdmiProperties; import android.view.KeyEvent; @@ -133,7 +132,6 @@ public class HdmiCecLocalDevicePlaybackTest { } }; - mHdmiControlService.writeBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, true); mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService); mHdmiCecLocalDevicePlayback.init(); mHdmiControlService.setIoLooper(mMyLooper); @@ -560,7 +558,9 @@ public class HdmiCecLocalDevicePlaybackTest { HdmiControlManager.POWER_CONTROL_MODE_TV); mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000, "HdmiCecLocalDevicePlaybackTest"); - mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true); + mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, + HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED); mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF); mTestLooper.dispatchAll(); @@ -580,7 +580,9 @@ public class HdmiCecLocalDevicePlaybackTest { HdmiControlManager.POWER_CONTROL_MODE_BROADCAST); mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000, "HdmiCecLocalDevicePlaybackTest"); - mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true); + mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, + HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED); mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF); mTestLooper.dispatchAll(); @@ -600,7 +602,9 @@ public class HdmiCecLocalDevicePlaybackTest { HdmiControlManager.POWER_CONTROL_MODE_NONE); mHdmiCecLocalDevicePlayback.setActiveSource(ADDR_TV, 0x0000, "HdmiCecLocalDevicePlaybackTest"); - mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true); + mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, + HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED); mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF); mTestLooper.dispatchAll(); @@ -620,7 +624,9 @@ public class HdmiCecLocalDevicePlaybackTest { HdmiControlManager.POWER_CONTROL_MODE_TV); mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest"); - mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true); + mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, + HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED); mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF); mTestLooper.dispatchAll(); @@ -640,7 +646,9 @@ public class HdmiCecLocalDevicePlaybackTest { HdmiControlManager.POWER_CONTROL_MODE_BROADCAST); mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest"); - mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true); + mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, + HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED); mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF); mTestLooper.dispatchAll(); @@ -660,7 +668,9 @@ public class HdmiCecLocalDevicePlaybackTest { HdmiControlManager.POWER_CONTROL_MODE_NONE); mHdmiCecLocalDevicePlayback.setActiveSource(mPlaybackLogicalAddress, mPlaybackPhysicalAddress, "HdmiCecLocalDevicePlaybackTest"); - mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true); + mHdmiCecLocalDevicePlayback.mService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, + HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED); mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF); mTestLooper.dispatchAll(); diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java index ec806fabdff4..0f527f3713b2 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java @@ -15,6 +15,7 @@ */ package com.android.server.hdmi; +import static com.android.server.hdmi.Constants.ADDR_BROADCAST; import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1; import static com.android.server.hdmi.Constants.ADDR_TV; import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC; @@ -269,6 +270,30 @@ public class HdmiCecLocalDeviceTvTest { } @Test + public void tvSendStandbyOnSleep_Enabled() { + mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, + HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_ENABLED); + mTestLooper.dispatchAll(); + mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF); + mTestLooper.dispatchAll(); + HdmiCecMessage standby = HdmiCecMessageBuilder.buildStandby(ADDR_TV, ADDR_BROADCAST); + assertThat(mNativeWrapper.getResultMessages()).contains(standby); + } + + @Test + public void tvSendStandbyOnSleep_Disabled() { + mHdmiCecLocalDeviceTv.mService.getHdmiCecConfig().setIntValue( + HdmiControlManager.CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP, + HdmiControlManager.TV_SEND_STANDBY_ON_SLEEP_DISABLED); + mTestLooper.dispatchAll(); + mHdmiControlService.onStandby(HdmiControlService.STANDBY_SCREEN_OFF); + mTestLooper.dispatchAll(); + HdmiCecMessage standby = HdmiCecMessageBuilder.buildStandby(ADDR_TV, ADDR_BROADCAST); + assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standby); + } + + @Test public void getRcFeatures() { ArrayList<Integer> features = new ArrayList<>(mHdmiCecLocalDeviceTv.getRcFeatures()); assertThat(features.contains(Constants.RC_PROFILE_TV_NONE)).isTrue(); diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 4db7ce2e6ef5..df19aeb13707 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -2051,6 +2051,7 @@ public class NetworkPolicyManagerServiceTest { final LinkProperties prop = new LinkProperties(); prop.setInterfaceName(TEST_IFACE); final NetworkCapabilities networkCapabilities = new NetworkCapabilities(); + networkCapabilities.setSSID(TEST_SSID); return new NetworkState(info, prop, networkCapabilities, null, null, TEST_SSID); } diff --git a/services/tests/shortcutmanagerutils/OWNERS b/services/tests/shortcutmanagerutils/OWNERS new file mode 100644 index 000000000000..d825dfd7cf00 --- /dev/null +++ b/services/tests/shortcutmanagerutils/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/pm/OWNERS diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java index ce96771c8c27..db241de246f6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java @@ -16,9 +16,6 @@ package com.android.server.wm; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; - import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; @@ -26,22 +23,17 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; -import android.app.IApplicationThread; import android.content.Intent; -import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import androidx.test.filters.SmallTest; import com.android.server.wm.ActivityStarter.Factory; -import com.android.server.wm.ActivityTaskSupervisor.PendingActivityLaunch; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.Random; - /** * Tests for the {@link ActivityStartController} class. * @@ -66,36 +58,6 @@ public class ActivityStartControllerTests extends WindowTestsBase { } /** - * Ensures that pending launches are processed. - */ - @Test - public void testPendingActivityLaunches() { - final Random random = new Random(); - - final ActivityRecord activity = new ActivityBuilder(mAtm).build(); - final ActivityRecord source = new ActivityBuilder(mAtm) - .setCreateTask(true) - .build(); - final int startFlags = random.nextInt(); - final Task rootTask = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final WindowProcessController wpc = new WindowProcessController(mAtm, - mAtm.mContext.getApplicationInfo(), "name", 12345, - UserHandle.getUserId(12345), mock(Object.class), - mock(WindowProcessListener.class)); - wpc.setThread(mock(IApplicationThread.class)); - - mController.addPendingActivityLaunch( - new PendingActivityLaunch(activity, source, startFlags, rootTask, wpc, null)); - final boolean resume = random.nextBoolean(); - mController.doPendingActivityLaunches(resume); - - verify(mStarter, times(1)).startResolvedActivity(eq(activity), eq(source), eq(null), - eq(null), eq(startFlags), eq(resume), eq(null), eq(null), eq(null)); - } - - - /** * Ensures instances are recycled after execution. */ @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 4bfc83742c04..36adf28b276a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -27,7 +27,6 @@ import static android.app.ActivityManager.START_NOT_VOICE_COMPATIBLE; import static android.app.ActivityManager.START_PERMISSION_DENIED; import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION; import static android.app.ActivityManager.START_SUCCESS; -import static android.app.ActivityManager.START_SWITCHES_CANCELED; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; @@ -119,7 +118,6 @@ public class ActivityStarterTests extends WindowTestsBase { private static final int PRECONDITION_DIFFERENT_UID = 1 << 7; private static final int PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION = 1 << 8; private static final int PRECONDITION_CANNOT_START_ANY_ACTIVITY = 1 << 9; - private static final int PRECONDITION_DISALLOW_APP_SWITCHING = 1 << 10; private static final int FAKE_CALLING_UID = 666; private static final int FAKE_REAL_CALLING_UID = 667; @@ -153,8 +151,6 @@ public class ActivityStarterTests extends WindowTestsBase { | PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION, START_NOT_VOICE_COMPATIBLE); verifyStartActivityPreconditions(PRECONDITION_CANNOT_START_ANY_ACTIVITY, START_ABORTED); - verifyStartActivityPreconditions(PRECONDITION_DISALLOW_APP_SWITCHING, - START_SWITCHES_CANCELED); } private static boolean containsConditions(int preconditions, int mask) { @@ -244,11 +240,6 @@ public class ActivityStarterTests extends WindowTestsBase { intent.setComponent(source.mActivityComponent); } - if (containsConditions(preconditions, PRECONDITION_DISALLOW_APP_SWITCHING)) { - doReturn(false).when(service).checkAppSwitchAllowedLocked( - anyInt(), anyInt(), anyInt(), anyInt(), any()); - } - if (containsConditions(preconditions, PRECONDITION_CANNOT_START_ANY_ACTIVITY)) { doReturn(false).when(service.mTaskSupervisor).checkStartAnyActivityPermission( any(), any(), any(), anyInt(), anyInt(), anyInt(), any(), any(), diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 4f44a06914a4..7215cd5e5559 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -4715,6 +4715,12 @@ public class CarrierConfigManager { "default_rtt_mode_int"; /** + * Indicates whether RTT is supported while roaming. + */ + public static final String KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL = + "rtt_supported_while_roaming_bool"; + + /** * Indicates if auto-configuration server is used for the RCS config * Reference: GSMA RCC.14 */ @@ -5090,6 +5096,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false); sDefaults.putBoolean(KEY_TTY_SUPPORTED_BOOL, true); sDefaults.putBoolean(KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL, false); + sDefaults.putBoolean(KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL, false); sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false); sDefaults.putBoolean(KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL, true); sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null); diff --git a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt index e9227e94da98..eb04f6907748 100644 --- a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt +++ b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt @@ -131,6 +131,10 @@ class PlatformCompatCommandNotInstalledTest { assertThat(platformCompat.isChangeEnabled(TEST_CHANGE_ID, appInfo)).isEqualTo(params.result) } - private fun command(command: String) = - FileReader(uiAutomation.executeShellCommand(command).fileDescriptor).readText() + private fun command(command: String): String { + val fileDescriptor = uiAutomation.executeShellCommand(command) + return String(ParcelFileDescriptor.AutoCloseInputStream(fileDescriptor).use { + inputStream -> inputStream.readBytes() + }) + } } diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt index 16c486562f53..083c8c8741da 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt @@ -38,6 +38,7 @@ import android.net.metrics.IpConnectivityLog import android.os.ConditionVariable import android.os.IBinder import android.os.INetworkManagementService +import android.os.UserHandle import android.testing.TestableContext import android.util.Log import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -55,10 +56,13 @@ import org.junit.Before import org.junit.BeforeClass import org.junit.Test import org.junit.runner.RunWith +import org.mockito.AdditionalAnswers import org.mockito.Mock import org.mockito.Mockito.any +import org.mockito.Mockito.anyInt import org.mockito.Mockito.doNothing import org.mockito.Mockito.doReturn +import org.mockito.Mockito.eq import org.mockito.Mockito.mock import org.mockito.Mockito.spy import org.mockito.MockitoAnnotations @@ -143,7 +147,10 @@ class ConnectivityServiceIntegrationTest { @Before fun setUp() { MockitoAnnotations.initMocks(this) - doNothing().`when`(context).sendStickyBroadcastAsUser(any(), any(), any()) + val asUserCtx = mock(Context::class.java, AdditionalAnswers.delegatesTo<Context>(context)) + doReturn(UserHandle.ALL).`when`(asUserCtx).user + doReturn(asUserCtx).`when`(context).createContextAsUser(eq(UserHandle.ALL), anyInt()) + doNothing().`when`(context).sendStickyBroadcast(any(), any()) networkStackClient = TestNetworkStackClient(realContext) networkStackClient.init() diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt index 9ba56e44fe88..91fcbc0fd5d7 100644 --- a/tests/net/java/android/net/NetworkTemplateTest.kt +++ b/tests/net/java/android/net/NetworkTemplateTest.kt @@ -67,6 +67,7 @@ class NetworkTemplateTest { val caps = NetworkCapabilities().apply { setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false) setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true) + setSSID(ssid) } return NetworkState(info, lp, caps, mock(Network::class.java), subscriberId, ssid) } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index c5e6c3507ebf..b3092b92989d 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -201,6 +201,7 @@ import android.net.SocketKeepalive; import android.net.UidRange; import android.net.UidRangeParcel; import android.net.Uri; +import android.net.VpnInfo; import android.net.VpnManager; import android.net.metrics.IpConnectivityLog; import android.net.shared.NetworkMonitorUtils; @@ -245,7 +246,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.app.IBatteryStats; import com.android.internal.net.VpnConfig; -import com.android.internal.net.VpnInfo; import com.android.internal.net.VpnProfile; import com.android.internal.util.ArrayUtils; import com.android.internal.util.WakeupMessage; @@ -8323,8 +8323,7 @@ public class ConnectivityServiceTest { assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid); mMockVpn.setVpnType(vpnType); - final VpnInfo vpnInfo = new VpnInfo(); - vpnInfo.ownerUid = vpnOwnerUid; + final VpnInfo vpnInfo = new VpnInfo(vpnOwnerUid, null, null); mMockVpn.setVpnInfo(vpnInfo); } diff --git a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java b/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java index 3aafe0b075f2..1b33930e96a9 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsBaseTest.java @@ -33,8 +33,7 @@ import static android.net.NetworkStats.TAG_NONE; import static org.junit.Assert.assertEquals; import android.net.NetworkStats; - -import com.android.internal.net.VpnInfo; +import android.net.VpnInfo; /** Superclass with utilities for NetworkStats(Service|Factory)Test */ abstract class NetworkStatsBaseTest { @@ -113,10 +112,6 @@ abstract class NetworkStatsBaseTest { } static VpnInfo createVpnInfo(String vpnIface, String[] underlyingIfaces) { - VpnInfo info = new VpnInfo(); - info.ownerUid = UID_VPN; - info.vpnIface = vpnIface; - info.underlyingIfaces = underlyingIfaces; - return info; + return new VpnInfo(UID_VPN, vpnIface, underlyingIfaces); } } diff --git a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java index e4996d981fac..76647a69de33 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java @@ -36,13 +36,13 @@ import static org.junit.Assert.fail; import android.content.res.Resources; import android.net.NetworkStats; import android.net.TrafficStats; +import android.net.VpnInfo; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.frameworks.tests.net.R; -import com.android.internal.net.VpnInfo; import libcore.io.IoUtils; import libcore.io.Streams; diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index c7836297df75..b4e37de2267f 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -21,7 +21,6 @@ import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_VPN; import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.DEFAULT_NETWORK_YES; @@ -44,6 +43,7 @@ import static android.net.NetworkStatsHistory.FIELD_ALL; import static android.net.NetworkTemplate.NETWORK_TYPE_ALL; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateMobileWithRatType; +import static android.net.NetworkTemplate.buildTemplateWifi; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; import static android.net.TrafficStats.MB_IN_BYTES; import static android.net.TrafficStats.UID_REMOVED; @@ -86,6 +86,7 @@ import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; +import android.net.VpnInfo; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.os.ConditionVariable; import android.os.Handler; @@ -104,7 +105,6 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.server.net.NetworkStatsService.NetworkStatsSettings; @@ -146,7 +146,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { private static final String IMSI_2 = "310260"; private static final String TEST_SSID = "AndroidAP"; - private static NetworkTemplate sTemplateWifi = buildTemplateWifiWildcard(); + private static NetworkTemplate sTemplateWifi = buildTemplateWifi(TEST_SSID); private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1); private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2); @@ -291,7 +291,6 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); - // modify some number on wifi, and trigger poll event incrementCurrentTime(HOUR_IN_MILLIS); expectDefaultSettings(); @@ -567,61 +566,6 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { } @Test - public void testUid3gWimaxCombinedByTemplate() throws Exception { - // pretend that network comes online - expectDefaultSettings(); - NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)}; - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(buildEmptyStats()); - - mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]); - - // create some traffic - incrementCurrentTime(HOUR_IN_MILLIS); - expectDefaultSettings(); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) - .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); - mService.incrementOperationCount(UID_RED, 0xF00D, 5); - - forcePollAndWaitForIdle(); - - // verify service recorded history - assertUidTotal(sTemplateImsi1, UID_RED, 1024L, 8L, 1024L, 8L, 5); - - - // now switch over to wimax network - incrementCurrentTime(HOUR_IN_MILLIS); - expectDefaultSettings(); - states = new NetworkState[] {buildWimaxState(TEST_IFACE2)}; - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) - .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); - - mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]); - forcePollAndWaitForIdle(); - - - // create traffic on second network - incrementCurrentTime(HOUR_IN_MILLIS); - expectDefaultSettings(); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) - .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .insertEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L) - .insertEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L)); - mService.incrementOperationCount(UID_RED, 0xFAAD, 5); - - forcePollAndWaitForIdle(); - - // verify that ALL_MOBILE template combines both - assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 1280L, 10L, 10); - } - - @Test public void testMobileStatsByRatType() throws Exception { final NetworkTemplate template3g = buildTemplateMobileWithRatType(null, TelephonyManager.NETWORK_TYPE_UMTS); @@ -1503,6 +1447,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, !isMetered); capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true); capabilities.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); + capabilities.setSSID(TEST_SSID); return new NetworkState(info, prop, capabilities, WIFI_NETWORK, null, TEST_SSID); } @@ -1524,17 +1469,6 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { return new NetworkState(info, prop, capabilities, MOBILE_NETWORK, subscriberId, null); } - private static NetworkState buildWimaxState(@NonNull String iface) { - final NetworkInfo info = new NetworkInfo(TYPE_WIMAX, 0, null, null); - info.setDetailedState(DetailedState.CONNECTED, null, null); - final LinkProperties prop = new LinkProperties(); - prop.setInterfaceName(iface); - final NetworkCapabilities capabilities = new NetworkCapabilities(); - capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false); - capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true); - return new NetworkState(info, prop, capabilities, MOBILE_NETWORK, null, null); - } - private NetworkStats buildEmptyStats() { return new NetworkStats(getElapsedRealtime(), 0); } diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java index dfd0c8a75172..86a15912b6b4 100644 --- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java +++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java @@ -28,6 +28,7 @@ import androidx.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.Arrays; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) @@ -39,6 +40,12 @@ public class VcnGatewayConnectionConfigTest { NetworkCapabilities.NET_CAPABILITY_INTERNET, NetworkCapabilities.NET_CAPABILITY_MMS }; public static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN}; + + static { + Arrays.sort(EXPOSED_CAPS); + Arrays.sort(UNDERLYING_CAPS); + } + public static final long[] RETRY_INTERVALS_MS = new long[] { TimeUnit.SECONDS.toMillis(5), @@ -124,12 +131,13 @@ public class VcnGatewayConnectionConfigTest { public void testBuilderAndGetters() { final VcnGatewayConnectionConfig config = buildTestConfig(); - for (int cap : EXPOSED_CAPS) { - config.hasExposedCapability(cap); - } - for (int cap : UNDERLYING_CAPS) { - config.requiresUnderlyingCapability(cap); - } + int[] exposedCaps = config.getExposedCapabilities(); + Arrays.sort(exposedCaps); + assertArrayEquals(EXPOSED_CAPS, exposedCaps); + + int[] underlyingCaps = config.getRequiredUnderlyingCapabilities(); + Arrays.sort(underlyingCaps); + assertArrayEquals(UNDERLYING_CAPS, underlyingCaps); assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMs()); assertEquals(MAX_MTU, config.getMaxMtu()); diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index 29cfdb6fd5c6..f0cdde33f822 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -18,6 +18,7 @@ package com.android.server; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; +import static com.android.server.vcn.VcnTestUtils.setupSystemService; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -138,11 +139,16 @@ public class VcnManagementServiceTest { private final IBinder mMockIBinder = mock(IBinder.class); public VcnManagementServiceTest() throws Exception { - setupSystemService(mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); - setupSystemService(mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class); setupSystemService( - mSubMgr, Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class); - setupSystemService(mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class); + mMockContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class); + setupSystemService( + mMockContext, mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class); + setupSystemService( + mMockContext, + mSubMgr, + Context.TELEPHONY_SUBSCRIPTION_SERVICE, + SubscriptionManager.class); + setupSystemService(mMockContext, mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class); doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName(); @@ -186,11 +192,6 @@ public class VcnManagementServiceTest { mTestLooper.dispatchAll(); } - private void setupSystemService(Object service, String name, Class<?> serviceClass) { - doReturn(name).when(mMockContext).getSystemServiceName(serviceClass); - doReturn(service).when(mMockContext).getSystemService(name); - } - private void setupMockedCarrierPrivilege(boolean isPrivileged) { doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO)) .when(mSubMgr) diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java new file mode 100644 index 000000000000..4ecd21503165 --- /dev/null +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -0,0 +1,84 @@ +/* + * 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 com.android.server.vcn; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Tests for VcnGatewayConnection.DisconnectedState */ +@RunWith(AndroidJUnit4.class) +@SmallTest +public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnectionTestBase { + @Before + public void setUp() throws Exception { + super.setUp(); + + mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectedState); + mTestLooper.dispatchAll(); + } + + @Test + public void testEnterWhileNotRunningTriggersQuit() throws Exception { + final VcnGatewayConnection vgc = + new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps); + + vgc.setIsRunning(false); + vgc.transitionTo(vgc.mDisconnectedState); + mTestLooper.dispatchAll(); + + assertNull(vgc.getCurrentState()); + } + + @Test + public void testNetworkChangesTriggerStateTransitions() throws Exception { + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState()); + } + + @Test + public void testNullNetworkDoesNotTriggerStateTransition() throws Exception { + mGatewayConnection + .getUnderlyingNetworkTrackerCallback() + .onSelectedUnderlyingNetworkChanged(null); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); + } + + @Test + public void testTeardown() throws Exception { + mGatewayConnection.teardownAsynchronously(); + mTestLooper.dispatchAll(); + + assertNull(mGatewayConnection.getCurrentState()); + verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any()); + } +} diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java new file mode 100644 index 000000000000..1725dd983115 --- /dev/null +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -0,0 +1,105 @@ +/* + * 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 com.android.server.vcn; + +import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord; +import static com.android.server.vcn.VcnTestUtils.setupIpSecManager; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +import android.annotation.NonNull; +import android.content.Context; +import android.net.IpSecManager; +import android.net.IpSecTunnelInterfaceResponse; +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.vcn.VcnGatewayConnectionConfig; +import android.net.vcn.VcnGatewayConnectionConfigTest; +import android.os.ParcelUuid; +import android.os.test.TestLooper; + +import com.android.server.IpSecService; + +import org.junit.Before; + +import java.util.UUID; + +public class VcnGatewayConnectionTestBase { + protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID()); + protected static final int TEST_IPSEC_TUNNEL_RESOURCE_ID = 1; + protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE"; + protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 = + new UnderlyingNetworkRecord( + new Network(0), + new NetworkCapabilities(), + new LinkProperties(), + false /* blocked */); + protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 = + new UnderlyingNetworkRecord( + new Network(1), + new NetworkCapabilities(), + new LinkProperties(), + false /* blocked */); + + @NonNull protected final Context mContext; + @NonNull protected final TestLooper mTestLooper; + @NonNull protected final VcnNetworkProvider mVcnNetworkProvider; + @NonNull protected final VcnContext mVcnContext; + @NonNull protected final VcnGatewayConnectionConfig mConfig; + @NonNull protected final VcnGatewayConnection.Dependencies mDeps; + @NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker; + + @NonNull protected final IpSecService mIpSecSvc; + + protected VcnGatewayConnection mGatewayConnection; + + public VcnGatewayConnectionTestBase() { + mContext = mock(Context.class); + mTestLooper = new TestLooper(); + mVcnNetworkProvider = mock(VcnNetworkProvider.class); + mVcnContext = mock(VcnContext.class); + mConfig = VcnGatewayConnectionConfigTest.buildTestConfig(); + mDeps = mock(VcnGatewayConnection.Dependencies.class); + mUnderlyingNetworkTracker = mock(UnderlyingNetworkTracker.class); + + mIpSecSvc = mock(IpSecService.class); + setupIpSecManager(mContext, mIpSecSvc); + + doReturn(mContext).when(mVcnContext).getContext(); + doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper(); + doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); + + doReturn(mUnderlyingNetworkTracker) + .when(mDeps) + .newUnderlyingNetworkTracker(any(), any(), any()); + } + + @Before + public void setUp() throws Exception { + IpSecTunnelInterfaceResponse resp = + new IpSecTunnelInterfaceResponse( + IpSecManager.Status.OK, + TEST_IPSEC_TUNNEL_RESOURCE_ID, + TEST_IPSEC_TUNNEL_IFACE); + doReturn(resp).when(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any()); + + mGatewayConnection = new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps); + } +} diff --git a/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java b/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java new file mode 100644 index 000000000000..2b1080650d6d --- /dev/null +++ b/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java @@ -0,0 +1,44 @@ +/* + * 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 com.android.server.vcn; + +import static org.mockito.Mockito.doReturn; + +import android.content.Context; +import android.net.IpSecManager; + +import com.android.server.IpSecService; + +public class VcnTestUtils { + /** Mock system services by directly mocking the *Manager interface. */ + public static void setupSystemService( + Context mockContext, Object service, String name, Class<?> serviceClass) { + doReturn(name).when(mockContext).getSystemServiceName(serviceClass); + doReturn(service).when(mockContext).getSystemService(name); + } + + /** Mock IpSecService by mocking the underlying service binder. */ + public static IpSecManager setupIpSecManager(Context mockContext, IpSecService service) { + doReturn(Context.IPSEC_SERVICE).when(mockContext).getSystemServiceName(IpSecManager.class); + + final IpSecManager ipSecMgr = new IpSecManager(mockContext, service); + doReturn(ipSecMgr).when(mockContext).getSystemService(Context.IPSEC_SERVICE); + + // Return to ensure this doesn't get reaped. + return ipSecMgr; + } +} |