diff options
145 files changed, 4879 insertions, 1799 deletions
diff --git a/api/Android.bp b/api/Android.bp index 2c2bb65402ea..4a641f3519eb 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -312,3 +312,49 @@ genrule { out: ["combined-removed-dex.txt"], cmd: "$(location gen_combined_removed_dex.sh) $(location metalava) $(genDir) $(in) > $(out)", } + +genrule { + name: "services-system-server-current.txt", + srcs: [ + ":service-permission{.system-server.api.txt}", + ":non-updatable-system-server-current.txt", + ], + out: ["system-server-current.txt"], + tools: ["metalava"], + cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + dists: [ + { + targets: ["droidcore"], + dir: "api", + dest: "system-server-current.txt", + }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/system-server/api", + dest: "merge-android.txt", + }, + ], +} + +genrule { + name: "services-system-server-removed.txt", + srcs: [ + ":service-permission{.system-server.removed-api.txt}", + ":non-updatable-system-server-removed.txt", + ], + out: ["system-server-removed.txt"], + tools: ["metalava"], + cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)", + dists: [ + { + targets: ["droidcore"], + dir: "api", + dest: "system-server-removed.txt", + }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/system-server/api", + dest: "merge-removed.txt", + }, + ], +} diff --git a/config/dirty-image-objects b/config/dirty-image-objects index 2dfe0197d898..dfd091cc1aff 100644 --- a/config/dirty-image-objects +++ b/config/dirty-image-objects @@ -28,359 +28,359 @@ # Then, grep for lines containing "Private dirty object" from the output. # This particular file was generated by dumping systemserver and systemui. # -android.accounts.Account -android.accounts.OnAccountsUpdateListener -android.animation.LayoutTransition -android.app.ActivityManager -android.app.ActivityManager$OnUidImportanceListener -android.app.ActivityTaskManager -android.app.ActivityThread -android.app.admin.DevicePolicyManager -android.app.AlarmManager -android.app.Application -android.app.AppOpsManager -android.app.backup.BackupManager -android.app.ContextImpl -android.app.INotificationManager -android.app.Notification$BigPictureStyle -android.app.Notification$BigTextStyle -android.app.Notification$InboxStyle -android.app.NotificationChannel -android.app.NotificationChannelGroup -android.app.NotificationManager -android.app.PendingIntent -android.app.PendingIntent$OnFinished -android.app.QueuedWork -android.app.ResourcesManager -android.app.WallpaperManager -android.app.WindowConfiguration -android.bluetooth.BluetoothAdapter -android.bluetooth.BluetoothDevice -android.bluetooth.BluetoothProfile -android.bluetooth.IBluetoothA2dp -android.bluetooth.IBluetoothHeadsetPhone -android.bluetooth.IBluetoothHidDevice -android.bluetooth.IBluetoothHidHost -android.bluetooth.IBluetoothMap -android.bluetooth.IBluetoothPan -android.bluetooth.IBluetoothPbap -android.bluetooth.IBluetoothSap -android.content.ClipboardManager$OnPrimaryClipChangedListener -android.content.ComponentName -android.content.ContentProvider$PipeDataWriter -android.content.ContentResolver -android.content.Context -android.content.Intent -android.content.pm.PackageManager$OnPermissionsChangedListener -android.content.pm.VersionedPackage -android.content.res.Configuration -android.content.SharedPreferences$OnSharedPreferenceChangeListener -android.database.CursorWindow -android.database.sqlite.SQLiteCompatibilityWalFlags -android.database.sqlite.SQLiteDatabase$CursorFactory -android.database.sqlite.SQLiteGlobal -android.database.sqlite.SQLiteTransactionListener -android.ddm.DdmHandleAppName -android.graphics.Bitmap -android.graphics.Canvas -android.graphics.drawable.AdaptiveIconDrawable -android.graphics.drawable.ColorDrawable -android.graphics.drawable.GradientDrawable -android.graphics.drawable.Icon -android.graphics.drawable.InsetDrawable -android.graphics.drawable.RippleDrawable -android.graphics.drawable.VectorDrawable$VGroup -android.graphics.ImageDecoder -android.graphics.Rect -android.graphics.TemporaryBuffer -android.hardware.biometrics.BiometricSourceType -android.hardware.display.ColorDisplayManager$ColorDisplayManagerInternal -android.hardware.display.DisplayManagerGlobal -android.hardware.display.NightDisplayListener$Callback -android.hardware.input.InputManager -android.hardware.input.InputManager$InputDeviceListener -android.hardware.SensorPrivacyManager -android.hardware.SystemSensorManager -android.icu.impl.OlsonTimeZone -android.icu.text.BreakIterator -android.icu.text.Collator -android.icu.text.DateFormat$BooleanAttribute -android.icu.text.DateTimePatternGenerator$DTPGflags -android.icu.text.PluralRules$Operand -android.icu.util.TimeZone -android.location.GpsStatus$Listener -android.location.LocationListener -android.media.AudioManager -android.media.MediaRouter -android.media.PlayerBase -android.media.session.MediaSessionManager -android.net.apf.ApfCapabilities -android.net.ConnectivityManager -android.net.ConnectivityManager$OnNetworkActiveListener -android.net.ConnectivityThread$Singleton -android.net.IpConfiguration$IpAssignment -android.net.IpConfiguration$ProxySettings -android.net.IpPrefix -android.net.LinkAddress -android.net.LinkProperties -android.net.Network -android.net.NetworkCapabilities -android.net.NetworkInfo -android.net.NetworkInfo$State -android.net.NetworkRequest -android.net.NetworkRequest$Type -android.net.RouteInfo -android.net.StringNetworkSpecifier -android.net.TrafficStats -android.net.UidRange -android.net.Uri$HierarchicalUri -android.net.Uri$StringUri -android.net.wifi.WifiManager -android.net.wifi.WifiManager$SoftApCallback -android.os.AsyncResult -android.os.AsyncTask -android.os.BinderProxy -android.os.Bundle -android.os.DeadObjectException -android.os.Environment -android.os.FileObserver -android.os.Handler -android.os.IDeviceIdleController -android.os.LocaleList -android.os.Looper -android.os.Message -android.os.ParcelUuid -android.os.Process -android.os.RecoverySystem -android.os.ServiceManager -android.os.storage.StorageManager -android.os.StrictMode -android.os.Trace -android.os.WorkSource -android.os.WorkSource$WorkChain -android.permission.PermissionManager -android.provider.FontsContract -android.provider.Settings$SettingNotFoundException -android.renderscript.RenderScriptCacheDir -android.security.IKeyChainService -android.security.keystore.AndroidKeyStoreProvider -android.security.net.config.ApplicationConfig -android.security.net.config.SystemCertificateSource$NoPreloadHolder -android.telecom.PhoneAccountHandle -android.telephony.AnomalyReporter -android.telephony.CellSignalStrengthCdma -android.telephony.CellSignalStrengthGsm -android.telephony.CellSignalStrengthLte -android.telephony.CellSignalStrengthNr -android.telephony.CellSignalStrengthTdscdma -android.telephony.CellSignalStrengthWcdma -android.telephony.DataSpecificRegistrationInfo -android.telephony.emergency.EmergencyNumber -android.telephony.ims.ImsMmTelManager$CapabilityCallback$CapabilityBinder -android.telephony.ims.ImsMmTelManager$RegistrationCallback$RegistrationBinder -android.telephony.ims.ImsReasonInfo -android.telephony.ims.ProvisioningManager$Callback$CallbackBinder -android.telephony.ModemActivityInfo -android.telephony.ModemInfo -android.telephony.NetworkRegistrationInfo -android.telephony.NetworkService -android.telephony.TelephonyManager -android.telephony.VoiceSpecificRegistrationInfo -android.text.format.DateFormat -android.text.method.SingleLineTransformationMethod -android.text.Selection$MemoryTextWatcher -android.text.SpanWatcher -android.text.style.AlignmentSpan -android.text.style.CharacterStyle -android.text.style.LeadingMarginSpan -android.text.style.LineBackgroundSpan -android.text.style.LineHeightSpan -android.text.style.MetricAffectingSpan -android.text.style.ReplacementSpan -android.text.style.SuggestionSpan -android.text.style.TabStopSpan -android.text.TextUtils -android.text.TextWatcher -android.transition.ChangeClipBounds -android.transition.ChangeImageTransform -android.transition.ChangeTransform -android.util.ArrayMap -android.util.ArraySet -android.util.DisplayMetrics -android.util.EventLog -android.util.Log -android.util.Patterns -android.view.AbsSavedState$1 -android.view.accessibility.AccessibilityManager -android.view.accessibility.AccessibilityManager$AccessibilityServicesStateChangeListener -android.view.accessibility.AccessibilityManager$TouchExplorationStateChangeListener -android.view.accessibility.AccessibilityNodeIdManager -android.view.autofill.AutofillManager -android.view.autofill.Helper -android.view.Choreographer -android.view.inputmethod.InputMethodManager -android.view.IWindowManager -android.view.PointerIcon -android.view.RemoteAnimationAdapter -android.view.ThreadedRenderer -android.view.View -android.view.View$OnHoverListener -android.view.ViewRootImpl -android.view.ViewStub -android.view.ViewStub$OnInflateListener -android.view.ViewTreeObserver -android.view.WindowManager$LayoutParams -android.view.WindowManagerGlobal -android.widget.ActionMenuPresenter$OverflowMenuButton -android.widget.ActionMenuView -android.widget.Button -android.widget.CheckBox -android.widget.FrameLayout -android.widget.ImageButton -android.widget.ImageView -android.widget.LinearLayout -android.widget.RelativeLayout -android.widget.SeekBar -android.widget.Space -android.widget.TextView -android.widget.Toolbar -byte[] -com.android.ims.ImsManager -com.android.internal.logging.MetricsLogger -com.android.internal.os.BackgroundThread -com.android.internal.os.BinderInternal -com.android.internal.os.BinderInternal$BinderProxyLimitListener -com.android.internal.os.RuntimeInit -com.android.internal.os.SomeArgs -com.android.internal.policy.DecorView -com.android.internal.statusbar.IStatusBarService -com.android.internal.telephony.AppSmsManager -android.telephony.CallerInfoAsyncQuery$OnQueryCompleteListener -com.android.internal.telephony.CarrierActionAgent -com.android.internal.telephony.cat.CatService -com.android.internal.telephony.cat.IconLoader -com.android.internal.telephony.cat.RilMessageDecoder -com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager -com.android.internal.telephony.cdma.EriManager -com.android.internal.telephony.CellularNetworkValidator -com.android.internal.telephony.CommandException -com.android.internal.telephony.dataconnection.DataConnection$DcActivatingState -com.android.internal.telephony.dataconnection.DataConnection$DcActiveState -com.android.internal.telephony.dataconnection.DataConnection$DcInactiveState -com.android.internal.telephony.dataconnection.DataEnabledSettings -com.android.internal.telephony.dataconnection.DcTracker -com.android.internal.telephony.euicc.EuiccCardController -com.android.internal.telephony.euicc.EuiccController -com.android.internal.telephony.GsmAlphabet -com.android.internal.telephony.GsmCdmaCallTracker -com.android.internal.telephony.GsmCdmaPhone -com.android.internal.telephony.IccPhoneBookInterfaceManager -com.android.internal.telephony.IccSmsInterfaceManager -com.android.internal.telephony.ims.ImsResolver -com.android.internal.telephony.imsphone.ImsExternalCallTracker -com.android.internal.telephony.imsphone.ImsPhone -com.android.internal.telephony.imsphone.ImsPhoneCallTracker -com.android.internal.telephony.ims.RcsMessageStoreController -com.android.internal.telephony.IntentBroadcaster -com.android.internal.telephony.ITelephonyRegistry$Stub$Proxy -com.android.internal.telephony.metrics.TelephonyMetrics -com.android.internal.telephony.MultiSimSettingController -com.android.internal.telephony.nano.CarrierIdProto$CarrierAttribute -com.android.internal.telephony.nano.CarrierIdProto$CarrierId -com.android.internal.telephony.nano.TelephonyProto$RilDataCall -com.android.internal.telephony.nano.TelephonyProto$SmsSession$Event -com.android.internal.telephony.nano.TelephonyProto$TelephonyCallSession$Event$RilCall -com.android.internal.telephony.NitzStateMachine -com.android.internal.telephony.PhoneConfigurationManager -com.android.internal.telephony.PhoneFactory -com.android.internal.telephony.PhoneSwitcher -com.android.internal.telephony.ProxyController -com.android.internal.telephony.RadioConfig -com.android.internal.telephony.RIL -com.android.internal.telephony.RILRequest -com.android.internal.telephony.RilWakelockInfo -com.android.internal.telephony.ServiceStateTracker -com.android.internal.telephony.SimActivationTracker -com.android.internal.telephony.SmsApplication -com.android.internal.telephony.SmsBroadcastUndelivered -com.android.internal.telephony.SmsStorageMonitor -com.android.internal.telephony.SmsUsageMonitor -com.android.internal.telephony.SubscriptionController -com.android.internal.telephony.SubscriptionInfoUpdater -com.android.internal.telephony.TelephonyComponentFactory -com.android.internal.telephony.TelephonyDevController -com.android.internal.telephony.TelephonyTester -com.android.internal.telephony.uicc.AdnRecordCache -com.android.internal.telephony.uicc.UiccCardApplication -com.android.internal.telephony.uicc.UiccController -com.android.internal.telephony.uicc.UiccProfile -com.android.internal.telephony.uicc.UiccStateChangedLauncher -com.android.internal.telephony.uicc.UsimFileHandler -com.android.internal.telephony.uicc.VoiceMailConstants -com.android.internal.util.LatencyTracker -com.android.internal.util.StateMachine$SmHandler -com.android.okhttp.OkHttpClient -com.android.okhttp.okio.AsyncTimeout -com.android.okhttp.okio.SegmentPool -com.android.phone.ecc.nano.ProtobufEccData$CountryInfo -com.android.phone.ecc.nano.ProtobufEccData$EccInfo -com.android.server.sip.SipWakeupTimer -com.android.server.SystemConfig -dalvik.system.BaseDexClassLoader -dalvik.system.BlockGuard -dalvik.system.CloseGuard -dalvik.system.RuntimeHooks -dalvik.system.SocketTagger -java.io.BufferedReader -java.lang.AssertionError -java.lang.Boolean -java.lang.Byte -java.lang.Character -java.lang.CharSequence -java.lang.Class -java.lang.IllegalAccessException -java.lang.IllegalStateException -java.lang.NoSuchMethodException -java.lang.NullPointerException -java.lang.Object -java.lang.Object[] -java.lang.ref.FinalizerReference -java.lang.Runnable -java.lang.SecurityException -java.lang.Short -java.lang.String[] -java.lang.System -java.lang.Thread -java.lang.Throwable -java.lang.UnsatisfiedLinkError -java.net.Inet6Address -java.net.Socket -java.net.SocketException -java.nio.Bits -java.nio.charset.Charset -java.security.interfaces.RSAPrivateKey -java.security.Provider -java.util.Collections -java.util.concurrent.Executor -java.util.GregorianCalendar -java.util.Locale -java.util.Locale$NoImagePreloadHolder -java.util.Scanner -java.util.Set -java.util.TimeZone -javax.net.SocketFactory -javax.net.ssl.HttpsURLConnection -javax.net.ssl.HttpsURLConnection$NoPreloadHolder -javax.net.ssl.SSLContext -javax.net.ssl.SSLSessionContext -javax.net.ssl.SSLSocketFactory -libcore.io.Libcore -libcore.io.Memory -libcore.net.NetworkSecurityPolicy -libcore.timezone.TimeZoneFinder -org.apache.http.params.HttpParams -sun.misc.Cleaner -sun.nio.ch.FileChannelImpl -sun.nio.ch.FileChannelImpl$Unmapper -sun.nio.fs.UnixChannelFactory -sun.security.jca.Providers +Landroid/accounts/Account; +Landroid/accounts/OnAccountsUpdateListener; +Landroid/animation/LayoutTransition; +Landroid/app/ActivityManager; +Landroid/app/ActivityManager$OnUidImportanceListener; +Landroid/app/ActivityTaskManager; +Landroid/app/ActivityThread; +Landroid/app/admin/DevicePolicyManager; +Landroid/app/AlarmManager; +Landroid/app/Application; +Landroid/app/AppOpsManager; +Landroid/app/backup/BackupManager; +Landroid/app/ContextImpl; +Landroid/app/INotificationManager; +Landroid/app/Notification$BigPictureStyle; +Landroid/app/Notification$BigTextStyle; +Landroid/app/Notification$InboxStyle; +Landroid/app/NotificationChannel; +Landroid/app/NotificationChannelGroup; +Landroid/app/NotificationManager; +Landroid/app/PendingIntent; +Landroid/app/PendingIntent$OnFinished; +Landroid/app/QueuedWork; +Landroid/app/ResourcesManager; +Landroid/app/WallpaperManager; +Landroid/app/WindowConfiguration; +Landroid/bluetooth/BluetoothAdapter; +Landroid/bluetooth/BluetoothDevice; +Landroid/bluetooth/BluetoothProfile; +Landroid/bluetooth/IBluetoothA2dp; +Landroid/bluetooth/IBluetoothHeadsetPhone; +Landroid/bluetooth/IBluetoothHidDevice; +Landroid/bluetooth/IBluetoothHidHost; +Landroid/bluetooth/IBluetoothMap; +Landroid/bluetooth/IBluetoothPan; +Landroid/bluetooth/IBluetoothPbap; +Landroid/bluetooth/IBluetoothSap; +Landroid/content/ClipboardManager$OnPrimaryClipChangedListener; +Landroid/content/ComponentName; +Landroid/content/ContentProvider$PipeDataWriter; +Landroid/content/ContentResolver; +Landroid/content/Context; +Landroid/content/Intent; +Landroid/content/pm/PackageManager$OnPermissionsChangedListener; +Landroid/content/pm/VersionedPackage; +Landroid/content/res/Configuration; +Landroid/content/SharedPreferences$OnSharedPreferenceChangeListener; +Landroid/database/CursorWindow; +Landroid/database/sqlite/SQLiteCompatibilityWalFlags; +Landroid/database/sqlite/SQLiteDatabase$CursorFactory; +Landroid/database/sqlite/SQLiteGlobal; +Landroid/database/sqlite/SQLiteTransactionListener; +Landroid/ddm/DdmHandleAppName; +Landroid/graphics/Bitmap; +Landroid/graphics/Canvas; +Landroid/graphics/drawable/AdaptiveIconDrawable; +Landroid/graphics/drawable/ColorDrawable; +Landroid/graphics/drawable/GradientDrawable; +Landroid/graphics/drawable/Icon; +Landroid/graphics/drawable/InsetDrawable; +Landroid/graphics/drawable/RippleDrawable; +Landroid/graphics/drawable/VectorDrawable$VGroup; +Landroid/graphics/ImageDecoder; +Landroid/graphics/Rect; +Landroid/graphics/TemporaryBuffer; +Landroid/hardware/biometrics/BiometricSourceType; +Landroid/hardware/display/ColorDisplayManager$ColorDisplayManagerInternal; +Landroid/hardware/display/DisplayManagerGlobal; +Landroid/hardware/display/NightDisplayListener$Callback; +Landroid/hardware/input/InputManager; +Landroid/hardware/input/InputManager$InputDeviceListener; +Landroid/hardware/SensorPrivacyManager; +Landroid/hardware/SystemSensorManager; +Landroid/icu/impl/OlsonTimeZone; +Landroid/icu/text/BreakIterator; +Landroid/icu/text/Collator; +Landroid/icu/text/DateFormat$BooleanAttribute; +Landroid/icu/text/DateTimePatternGenerator$DTPGflags; +Landroid/icu/text/PluralRules$Operand; +Landroid/icu/util/TimeZone; +Landroid/location/GpsStatus$Listener; +Landroid/location/LocationListener; +Landroid/media/AudioManager; +Landroid/media/MediaRouter; +Landroid/media/PlayerBase; +Landroid/media/session/MediaSessionManager; +Landroid/net/apf/ApfCapabilities; +Landroid/net/ConnectivityManager; +Landroid/net/ConnectivityManager$OnNetworkActiveListener; +Landroid/net/ConnectivityThread$Singleton; +Landroid/net/IpConfiguration$IpAssignment; +Landroid/net/IpConfiguration$ProxySettings; +Landroid/net/IpPrefix; +Landroid/net/LinkAddress; +Landroid/net/LinkProperties; +Landroid/net/Network; +Landroid/net/NetworkCapabilities; +Landroid/net/NetworkInfo; +Landroid/net/NetworkInfo$State; +Landroid/net/NetworkRequest; +Landroid/net/NetworkRequest$Type; +Landroid/net/RouteInfo; +Landroid/net/StringNetworkSpecifier; +Landroid/net/TrafficStats; +Landroid/net/UidRange; +Landroid/net/Uri$HierarchicalUri; +Landroid/net/Uri$StringUri; +Landroid/net/wifi/WifiManager; +Landroid/net/wifi/WifiManager$SoftApCallback; +Landroid/os/AsyncResult; +Landroid/os/AsyncTask; +Landroid/os/BinderProxy; +Landroid/os/Bundle; +Landroid/os/DeadObjectException; +Landroid/os/Environment; +Landroid/os/FileObserver; +Landroid/os/Handler; +Landroid/os/IDeviceIdleController; +Landroid/os/LocaleList; +Landroid/os/Looper; +Landroid/os/Message; +Landroid/os/ParcelUuid; +Landroid/os/Process; +Landroid/os/RecoverySystem; +Landroid/os/ServiceManager; +Landroid/os/storage/StorageManager; +Landroid/os/StrictMode; +Landroid/os/Trace; +Landroid/os/WorkSource; +Landroid/os/WorkSource$WorkChain; +Landroid/permission/PermissionManager; +Landroid/provider/FontsContract; +Landroid/provider/Settings$SettingNotFoundException; +Landroid/renderscript/RenderScriptCacheDir; +Landroid/security/IKeyChainService; +Landroid/security/keystore/AndroidKeyStoreProvider; +Landroid/security/net/config/ApplicationConfig; +Landroid/security/net/config/SystemCertificateSource$NoPreloadHolder; +Landroid/telecom/PhoneAccountHandle; +Landroid/telephony/AnomalyReporter; +Landroid/telephony/CellSignalStrengthCdma; +Landroid/telephony/CellSignalStrengthGsm; +Landroid/telephony/CellSignalStrengthLte; +Landroid/telephony/CellSignalStrengthNr; +Landroid/telephony/CellSignalStrengthTdscdma; +Landroid/telephony/CellSignalStrengthWcdma; +Landroid/telephony/DataSpecificRegistrationInfo; +Landroid/telephony/emergency/EmergencyNumber; +Landroid/telephony/ims/ImsMmTelManager$CapabilityCallback$CapabilityBinder; +Landroid/telephony/ims/ImsMmTelManager$RegistrationCallback$RegistrationBinder; +Landroid/telephony/ims/ImsReasonInfo; +Landroid/telephony/ims/ProvisioningManager$Callback$CallbackBinder; +Landroid/telephony/ModemActivityInfo; +Landroid/telephony/ModemInfo; +Landroid/telephony/NetworkRegistrationInfo; +Landroid/telephony/NetworkService; +Landroid/telephony/TelephonyManager; +Landroid/telephony/VoiceSpecificRegistrationInfo; +Landroid/text/format/DateFormat; +Landroid/text/method/SingleLineTransformationMethod; +Landroid/text/Selection$MemoryTextWatcher; +Landroid/text/SpanWatcher; +Landroid/text/style/AlignmentSpan; +Landroid/text/style/CharacterStyle; +Landroid/text/style/LeadingMarginSpan; +Landroid/text/style/LineBackgroundSpan; +Landroid/text/style/LineHeightSpan; +Landroid/text/style/MetricAffectingSpan; +Landroid/text/style/ReplacementSpan; +Landroid/text/style/SuggestionSpan; +Landroid/text/style/TabStopSpan; +Landroid/text/TextUtils; +Landroid/text/TextWatcher; +Landroid/transition/ChangeClipBounds; +Landroid/transition/ChangeImageTransform; +Landroid/transition/ChangeTransform; +Landroid/util/ArrayMap; +Landroid/util/ArraySet; +Landroid/util/DisplayMetrics; +Landroid/util/EventLog; +Landroid/util/Log; +Landroid/util/Patterns; +Landroid/view/AbsSavedState$1; +Landroid/view/accessibility/AccessibilityManager; +Landroid/view/accessibility/AccessibilityManager$AccessibilityServicesStateChangeListener; +Landroid/view/accessibility/AccessibilityManager$TouchExplorationStateChangeListener; +Landroid/view/accessibility/AccessibilityNodeIdManager; +Landroid/view/autofill/AutofillManager; +Landroid/view/autofill/Helper; +Landroid/view/Choreographer; +Landroid/view/inputmethod/InputMethodManager; +Landroid/view/IWindowManager; +Landroid/view/PointerIcon; +Landroid/view/RemoteAnimationAdapter; +Landroid/view/ThreadedRenderer; +Landroid/view/View; +Landroid/view/View$OnHoverListener; +Landroid/view/ViewRootImpl; +Landroid/view/ViewStub; +Landroid/view/ViewStub$OnInflateListener; +Landroid/view/ViewTreeObserver; +Landroid/view/WindowManager$LayoutParams; +Landroid/view/WindowManagerGlobal; +Landroid/widget/ActionMenuPresenter$OverflowMenuButton; +Landroid/widget/ActionMenuView; +Landroid/widget/Button; +Landroid/widget/CheckBox; +Landroid/widget/FrameLayout; +Landroid/widget/ImageButton; +Landroid/widget/ImageView; +Landroid/widget/LinearLayout; +Landroid/widget/RelativeLayout; +Landroid/widget/SeekBar; +Landroid/widget/Space; +Landroid/widget/TextView; +Landroid/widget/Toolbar; +[B +Lcom/android/ims/ImsManager; +Lcom/android/internal/logging/MetricsLogger; +Lcom/android/internal/os/BackgroundThread; +Lcom/android/internal/os/BinderInternal; +Lcom/android/internal/os/BinderInternal$BinderProxyLimitListener; +Lcom/android/internal/os/RuntimeInit; +Lcom/android/internal/os/SomeArgs; +Lcom/android/internal/policy/DecorView; +Lcom/android/internal/statusbar/IStatusBarService; +Lcom/android/internal/telephony/AppSmsManager; +Landroid/telephony/CallerInfoAsyncQuery$OnQueryCompleteListener; +Lcom/android/internal/telephony/CarrierActionAgent; +Lcom/android/internal/telephony/cat/CatService; +Lcom/android/internal/telephony/cat/IconLoader; +Lcom/android/internal/telephony/cat/RilMessageDecoder; +Lcom/android/internal/telephony/cdma/CdmaSubscriptionSourceManager; +Lcom/android/internal/telephony/cdma/EriManager; +Lcom/android/internal/telephony/CellularNetworkValidator; +Lcom/android/internal/telephony/CommandException; +Lcom/android/internal/telephony/dataconnection/DataConnection$DcActivatingState; +Lcom/android/internal/telephony/dataconnection/DataConnection$DcActiveState; +Lcom/android/internal/telephony/dataconnection/DataConnection$DcInactiveState; +Lcom/android/internal/telephony/dataconnection/DataEnabledSettings; +Lcom/android/internal/telephony/dataconnection/DcTracker; +Lcom/android/internal/telephony/euicc/EuiccCardController; +Lcom/android/internal/telephony/euicc/EuiccController; +Lcom/android/internal/telephony/GsmAlphabet; +Lcom/android/internal/telephony/GsmCdmaCallTracker; +Lcom/android/internal/telephony/GsmCdmaPhone; +Lcom/android/internal/telephony/IccPhoneBookInterfaceManager; +Lcom/android/internal/telephony/IccSmsInterfaceManager; +Lcom/android/internal/telephony/ims/ImsResolver; +Lcom/android/internal/telephony/imsphone/ImsExternalCallTracker; +Lcom/android/internal/telephony/imsphone/ImsPhone; +Lcom/android/internal/telephony/imsphone/ImsPhoneCallTracker; +Lcom/android/internal/telephony/ims/RcsMessageStoreController; +Lcom/android/internal/telephony/IntentBroadcaster; +Lcom/android/internal/telephony/ITelephonyRegistry$Stub$Proxy; +Lcom/android/internal/telephony/metrics/TelephonyMetrics; +Lcom/android/internal/telephony/MultiSimSettingController; +Lcom/android/internal/telephony/nano/CarrierIdProto$CarrierAttribute; +Lcom/android/internal/telephony/nano/CarrierIdProto$CarrierId; +Lcom/android/internal/telephony/nano/TelephonyProto$RilDataCall; +Lcom/android/internal/telephony/nano/TelephonyProto$SmsSession$Event; +Lcom/android/internal/telephony/nano/TelephonyProto$TelephonyCallSession$Event$RilCall; +Lcom/android/internal/telephony/NitzStateMachine; +Lcom/android/internal/telephony/PhoneConfigurationManager; +Lcom/android/internal/telephony/PhoneFactory; +Lcom/android/internal/telephony/PhoneSwitcher; +Lcom/android/internal/telephony/ProxyController; +Lcom/android/internal/telephony/RadioConfig; +Lcom/android/internal/telephony/RIL; +Lcom/android/internal/telephony/RILRequest; +Lcom/android/internal/telephony/RilWakelockInfo; +Lcom/android/internal/telephony/ServiceStateTracker; +Lcom/android/internal/telephony/SimActivationTracker; +Lcom/android/internal/telephony/SmsApplication; +Lcom/android/internal/telephony/SmsBroadcastUndelivered; +Lcom/android/internal/telephony/SmsStorageMonitor; +Lcom/android/internal/telephony/SmsUsageMonitor; +Lcom/android/internal/telephony/SubscriptionController; +Lcom/android/internal/telephony/SubscriptionInfoUpdater; +Lcom/android/internal/telephony/TelephonyComponentFactory; +Lcom/android/internal/telephony/TelephonyDevController; +Lcom/android/internal/telephony/TelephonyTester; +Lcom/android/internal/telephony/uicc/AdnRecordCache; +Lcom/android/internal/telephony/uicc/UiccCardApplication; +Lcom/android/internal/telephony/uicc/UiccController; +Lcom/android/internal/telephony/uicc/UiccProfile; +Lcom/android/internal/telephony/uicc/UiccStateChangedLauncher; +Lcom/android/internal/telephony/uicc/UsimFileHandler; +Lcom/android/internal/telephony/uicc/VoiceMailConstants; +Lcom/android/internal/util/LatencyTracker; +Lcom/android/internal/util/StateMachine$SmHandler; +Lcom/android/okhttp/OkHttpClient; +Lcom/android/okhttp/okio/AsyncTimeout; +Lcom/android/okhttp/okio/SegmentPool; +Lcom/android/phone/ecc/nano/ProtobufEccData$CountryInfo; +Lcom/android/phone/ecc/nano/ProtobufEccData$EccInfo; +Lcom/android/server/sip/SipWakeupTimer; +Lcom/android/server/SystemConfig; +Ldalvik/system/BaseDexClassLoader; +Ldalvik/system/BlockGuard; +Ldalvik/system/CloseGuard; +Ldalvik/system/RuntimeHooks; +Ldalvik/system/SocketTagger; +Ljava/io/BufferedReader; +Ljava/lang/AssertionError; +Ljava/lang/Boolean; +Ljava/lang/Byte; +Ljava/lang/Character; +Ljava/lang/CharSequence; +Ljava/lang/Class; +Ljava/lang/IllegalAccessException; +Ljava/lang/IllegalStateException; +Ljava/lang/NoSuchMethodException; +Ljava/lang/NullPointerException; +Ljava/lang/Object; +[Ljava/lang/Object; +Ljava/lang/ref/FinalizerReference; +Ljava/lang/Runnable; +Ljava/lang/SecurityException; +Ljava/lang/Short; +[Ljava/lang/String; +Ljava/lang/System; +Ljava/lang/Thread; +Ljava/lang/Throwable; +Ljava/lang/UnsatisfiedLinkError; +Ljava/net/Inet6Address; +Ljava/net/Socket; +Ljava/net/SocketException; +Ljava/nio/Bits; +Ljava/nio/charset/Charset; +Ljava/security/interfaces/RSAPrivateKey; +Ljava/security/Provider; +Ljava/util/Collections; +Ljava/util/concurrent/Executor; +Ljava/util/GregorianCalendar; +Ljava/util/Locale; +Ljava/util/Locale$NoImagePreloadHolder; +Ljava/util/Scanner; +Ljava/util/Set; +Ljava/util/TimeZone; +Ljavax/net/SocketFactory; +Ljavax/net/ssl/HttpsURLConnection; +Ljavax/net/ssl/HttpsURLConnection$NoPreloadHolder; +Ljavax/net/ssl/SSLContext; +Ljavax/net/ssl/SSLSessionContext; +Ljavax/net/ssl/SSLSocketFactory; +Llibcore/io/Libcore; +Llibcore/io/Memory; +Llibcore/net/NetworkSecurityPolicy; +Llibcore/timezone/TimeZoneFinder; +Lorg/apache/http/params/HttpParams; +Lsun/misc/Cleaner; +Lsun/nio/ch/FileChannelImpl; +Lsun/nio/ch/FileChannelImpl$Unmapper; +Lsun/nio/fs/UnixChannelFactory; +Lsun/security/jca/Providers; diff --git a/core/api/current.txt b/core/api/current.txt index cfb503757de1..5f2555a20f75 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -954,6 +954,7 @@ package android { field public static final int measureWithLargestChild = 16843476; // 0x10102d4 field public static final int mediaRouteButtonStyle = 16843693; // 0x10103ad field public static final int mediaRouteTypes = 16843694; // 0x10103ae + field public static final int memtagMode = 16844313; // 0x1010619 field public static final int menuCategory = 16843230; // 0x10101de field public static final int mimeGroup = 16844309; // 0x1010615 field public static final int mimeType = 16842790; // 0x1010026 @@ -977,6 +978,7 @@ package android { field public static final int multiArch = 16843918; // 0x101048e field public static final int multiprocess = 16842771; // 0x1010013 field public static final int name = 16842755; // 0x1010003 + field public static final int nativeHeapZeroInit = 16844314; // 0x101061a field public static final int navigationBarColor = 16843858; // 0x1010452 field public static final int navigationBarDividerColor = 16844141; // 0x101056d field public static final int navigationContentDescription = 16843969; // 0x10104c1 @@ -11461,6 +11463,8 @@ package android.content.pm { method public void dump(android.util.Printer, String); method public static CharSequence getCategoryTitle(android.content.Context, int); method public int getGwpAsanMode(); + method public int getMemtagMode(); + method @Nullable public Boolean isNativeHeapZeroInit(); method public boolean isProfileableByShell(); method public boolean isResourceOverlay(); method public boolean isVirtualPreload(); @@ -11510,6 +11514,10 @@ package android.content.pm { field public static final int GWP_ASAN_ALWAYS = 1; // 0x1 field public static final int GWP_ASAN_DEFAULT = -1; // 0xffffffff field public static final int GWP_ASAN_NEVER = 0; // 0x0 + field public static final int MEMTAG_ASYNC = 1; // 0x1 + field public static final int MEMTAG_DEFAULT = -1; // 0xffffffff + field public static final int MEMTAG_OFF = 0; // 0x0 + field public static final int MEMTAG_SYNC = 2; // 0x2 field public String appComponentFactory; field public String backupAgentName; field public int category; @@ -12039,6 +12047,7 @@ package android.content.pm { method public boolean getSyntheticAppDetailsActivityEnabled(@NonNull String); method @NonNull public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures(); method @Nullable public abstract String[] getSystemSharedLibraryNames(); + method @IntRange(from=0) public int getTargetSdkVersion(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException; method @Nullable public abstract CharSequence getText(@NonNull String, @StringRes int, @Nullable android.content.pm.ApplicationInfo); method @NonNull public abstract android.graphics.drawable.Drawable getUserBadgedDrawableForDensity(@NonNull android.graphics.drawable.Drawable, @NonNull android.os.UserHandle, @Nullable android.graphics.Rect, int); method @NonNull public abstract android.graphics.drawable.Drawable getUserBadgedIcon(@NonNull android.graphics.drawable.Drawable, @NonNull android.os.UserHandle); @@ -40971,7 +40980,6 @@ package android.telephony { public final class SignalStrengthUpdateRequest implements android.os.Parcelable { method public int describeContents(); - method @NonNull public android.os.IBinder getLiveToken(); method @NonNull public java.util.Collection<android.telephony.SignalThresholdInfo> getSignalThresholdInfos(); method public boolean isReportingRequestedWhileIdle(); method public void writeToParcel(@NonNull android.os.Parcel, int); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 4e7fc292f321..df348be89a92 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -14,6 +14,7 @@ package android { field public static final String ACCESS_MTP = "android.permission.ACCESS_MTP"; field public static final String ACCESS_NETWORK_CONDITIONS = "android.permission.ACCESS_NETWORK_CONDITIONS"; field public static final String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS"; + field public static final String ACCESS_RCS_USER_CAPABILITY_EXCHANGE = "android.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE"; field public static final String ACCESS_SHARED_LIBRARIES = "android.permission.ACCESS_SHARED_LIBRARIES"; field public static final String ACCESS_SHORTCUTS = "android.permission.ACCESS_SHORTCUTS"; field public static final String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER"; @@ -10541,6 +10542,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean matchesCurrentSimOperator(@NonNull String, int, @Nullable String); method public boolean needsOtaServiceProvisioning(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled(); + method @RequiresPermission(android.Manifest.permission.REBOOT) public int prepareForUnattendedReboot(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void reportDefaultNetworkStatus(boolean); method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback); @@ -10606,6 +10608,7 @@ package android.telephony { field public static final int CALL_WAITING_STATUS_ENABLED = 1; // 0x1 field public static final int CALL_WAITING_STATUS_NOT_SUPPORTED = 4; // 0x4 field public static final int CALL_WAITING_STATUS_UNKNOWN_ERROR = 3; // 0x3 + field public static final String CAPABILITY_ALLOWED_NETWORK_TYPES_USED = "CAPABILITY_ALLOWED_NETWORK_TYPES_USED"; field public static final String CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE = "CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE"; field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1 @@ -10660,6 +10663,9 @@ package android.telephony { field public static final int NR_DUAL_CONNECTIVITY_DISABLE = 2; // 0x2 field public static final int NR_DUAL_CONNECTIVITY_DISABLE_IMMEDIATE = 3; // 0x3 field public static final int NR_DUAL_CONNECTIVITY_ENABLE = 1; // 0x1 + field public static final int PREPARE_UNATTENDED_REBOOT_ERROR = 2; // 0x2 + field public static final int PREPARE_UNATTENDED_REBOOT_PIN_REQUIRED = 1; // 0x1 + field public static final int PREPARE_UNATTENDED_REBOOT_SUCCESS = 0; // 0x0 field public static final int RADIO_POWER_OFF = 0; // 0x0 field public static final int RADIO_POWER_ON = 1; // 0x1 field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2 @@ -12004,8 +12010,8 @@ package android.telephony.ims { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addOnPublishStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.OnPublishStateChangedListener) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getUcePublishState() throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeOnPublishStateChangedListener(@NonNull android.telephony.ims.RcsUceAdapter.OnPublishStateChangedListener) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestAvailability(@NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException; + method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, android.Manifest.permission.READ_CONTACTS}) public void requestAvailability(@NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException; + method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, android.Manifest.permission.READ_CONTACTS}) public void requestCapabilities(@NonNull java.util.List<android.net.Uri>, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException; field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2 field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 1; // 0x1 @@ -12290,7 +12296,7 @@ package android.telephony.ims.stub { } public static interface CapabilityExchangeEventListener.OptionsRequestCallback { - method public default void onRespondToCapabilityRequest(@NonNull android.telephony.ims.RcsContactUceCapability, boolean); + method public void onRespondToCapabilityRequest(@NonNull android.telephony.ims.RcsContactUceCapability, boolean); method public void onRespondToCapabilityRequestWithError(@IntRange(from=100, to=699) int, @NonNull String); } @@ -12775,21 +12781,10 @@ package android.uwb { public final class UwbManager { method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public long elapsedRealtimeResolutionNanos(); - method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public int getAngleOfArrivalSupport(); - method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public int getMaxRemoteDevicesPerInitiatorSession(); - method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public int getMaxRemoteDevicesPerResponderSession(); - method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public int getMaxSimultaneousSessions(); method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public android.os.PersistableBundle getSpecificationInfo(); - method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public java.util.List<java.lang.Integer> getSupportedChannelNumbers(); - method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public java.util.Set<java.lang.Integer> getSupportedPreambleCodeIndices(); - method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public boolean isRangingSupported(); method @NonNull @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public AutoCloseable openRangingSession(@NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull android.uwb.RangingSession.Callback); method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void registerAdapterStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.uwb.UwbManager.AdapterStateCallback); method @RequiresPermission(android.Manifest.permission.UWB_PRIVILEGED) public void unregisterAdapterStateCallback(@NonNull android.uwb.UwbManager.AdapterStateCallback); - field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D = 2; // 0x2 - field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL = 3; // 0x3 - field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL = 4; // 0x4 - field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE = 1; // 0x1 } public static interface UwbManager.AdapterStateCallback { diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 797253af394b..c1d9b9087ecb 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -2460,9 +2460,9 @@ public class AppOpsManager { false, // READ_MEDIA_AUDIO false, // WRITE_MEDIA_AUDIO false, // READ_MEDIA_VIDEO - false, // WRITE_MEDIA_VIDEO + true, // WRITE_MEDIA_VIDEO false, // READ_MEDIA_IMAGES - false, // WRITE_MEDIA_IMAGES + true, // WRITE_MEDIA_IMAGES true, // LEGACY_STORAGE false, // ACCESS_ACCESSIBILITY false, // READ_DEVICE_IDENTIFIERS diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 425073c92045..17e527d7e617 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -451,6 +451,19 @@ public class ApplicationPackageManager extends PackageManager { } @Override + public int getTargetSdkVersion(@NonNull String packageName) throws NameNotFoundException { + try { + int version = mPM.getTargetSdkVersion(packageName); + if (version != -1) { + return version; + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + throw new PackageManager.NameNotFoundException(packageName); + } + + @Override public ActivityInfo getActivityInfo(ComponentName className, int flags) throws NameNotFoundException { final int userId = getUserId(); diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index e32068fe4b39..6ec11693d69b 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -38,6 +38,8 @@ import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.Parcelling; +import com.android.internal.util.Parcelling.BuiltIn.ForBoolean; import com.android.server.SystemConfig; import java.lang.annotation.Retention; @@ -56,6 +58,8 @@ import java.util.UUID; * <application> tag. */ public class ApplicationInfo extends PackageItemInfo implements Parcelable { + private static ForBoolean sForBoolean = Parcelling.Cache.getOrCreate(ForBoolean.class); + /** * Default task affinity of all activities in this application. See * {@link ActivityInfo#taskAffinity} for more information. This comes @@ -1336,6 +1340,51 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { private @GwpAsanMode int gwpAsanMode; /** + * Default (unspecified) setting of Memtag. + */ + public static final int MEMTAG_DEFAULT = -1; + + /** + * Do not enable Memtag in this application or process. + */ + public static final int MEMTAG_OFF = 0; + + /** + * Enable Memtag in Async mode in this application or process. + */ + public static final int MEMTAG_ASYNC = 1; + + /** + * Enable Memtag in Sync mode in this application or process. + */ + public static final int MEMTAG_SYNC = 2; + + /** + * These constants need to match the values of memtagMode in application manifest. + * @hide + */ + @IntDef(prefix = {"MEMTAG_"}, value = { + MEMTAG_DEFAULT, + MEMTAG_OFF, + MEMTAG_ASYNC, + MEMTAG_SYNC, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface MemtagMode {} + + /** + * Indicates if the application has requested Memtag to be enabled, disabled, or left + * unspecified. Processes can override this setting. + */ + private @MemtagMode int memtagMode; + + /** + * Enable automatic zero-initialization of native heap memory allocations. + */ + @Nullable + private Boolean nativeHeapZeroInit; + + /** * Represents the default policy. The actual policy used will depend on other properties of * the application, e.g. the target SDK version. * @hide @@ -1479,6 +1528,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { if (gwpAsanMode != GWP_ASAN_DEFAULT) { pw.println(prefix + "gwpAsanMode=" + gwpAsanMode); } + if (memtagMode != MEMTAG_DEFAULT) { + pw.println(prefix + "memtagMode=" + memtagMode); + } + if (nativeHeapZeroInit != null) { + pw.println(prefix + "nativeHeapZeroInit=" + nativeHeapZeroInit); + } } super.dumpBack(pw, prefix); } @@ -1580,6 +1635,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { if (gwpAsanMode != GWP_ASAN_DEFAULT) { proto.write(ApplicationInfoProto.Detail.ENABLE_GWP_ASAN, gwpAsanMode); } + if (memtagMode != MEMTAG_DEFAULT) { + proto.write(ApplicationInfoProto.Detail.ENABLE_MEMTAG, memtagMode); + } + if (nativeHeapZeroInit != null) { + proto.write(ApplicationInfoProto.Detail.NATIVE_HEAP_ZERO_INIT, nativeHeapZeroInit); + } proto.end(detailToken); } proto.end(token); @@ -1690,6 +1751,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { hiddenUntilInstalled = orig.hiddenUntilInstalled; zygotePreloadName = orig.zygotePreloadName; gwpAsanMode = orig.gwpAsanMode; + memtagMode = orig.memtagMode; + nativeHeapZeroInit = orig.nativeHeapZeroInit; } public String toString() { @@ -1774,6 +1837,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeInt(hiddenUntilInstalled ? 1 : 0); dest.writeString8(zygotePreloadName); dest.writeInt(gwpAsanMode); + dest.writeInt(memtagMode); + sForBoolean.parcel(nativeHeapZeroInit, dest, parcelableFlags); } public static final @android.annotation.NonNull Parcelable.Creator<ApplicationInfo> CREATOR @@ -1855,6 +1920,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { hiddenUntilInstalled = source.readInt() != 0; zygotePreloadName = source.readString8(); gwpAsanMode = source.readInt(); + memtagMode = source.readInt(); + nativeHeapZeroInit = sForBoolean.unparcel(source); } /** @@ -2237,6 +2304,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { /** {@hide} */ public void setBaseResourcePath(String baseResourcePath) { publicSourceDir = baseResourcePath; } /** {@hide} */ public void setSplitResourcePaths(String[] splitResourcePaths) { splitPublicSourceDirs = splitResourcePaths; } /** {@hide} */ public void setGwpAsanMode(@GwpAsanMode int value) { gwpAsanMode = value; } + /** {@hide} */ public void setMemtagMode(@MemtagMode int value) { memtagMode = value; } + /** {@hide} */ public void setNativeHeapZeroInit(@Nullable Boolean value) { nativeHeapZeroInit = value; } /** {@hide} */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -2250,4 +2319,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { /** {@hide} */ public String[] getSplitResourcePaths() { return splitPublicSourceDirs; } @GwpAsanMode public int getGwpAsanMode() { return gwpAsanMode; } + @MemtagMode + public int getMemtagMode() { return memtagMode; } + @Nullable + public Boolean isNativeHeapZeroInit() { return nativeHeapZeroInit; } } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 5f8754efb47f..7e082d583a1c 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -82,6 +82,11 @@ interface IPackageManager { @UnsupportedAppUsage ApplicationInfo getApplicationInfo(String packageName, int flags ,int userId); + /** + * @return the target SDK for the given package name, or -1 if it cannot be retrieved + */ + int getTargetSdkVersion(String packageName); + @UnsupportedAppUsage ActivityInfo getActivityInfo(in ComponentName className, int flags, int userId); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 443ae358b8cd..8744a0e92e07 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -4256,6 +4256,15 @@ public abstract class PackageManager { } /** + * @return The target SDK version for the given package name. + * @throws NameNotFoundException if a package with the given name cannot be found on the system. + */ + @IntRange(from = 0) + public int getTargetSdkVersion(@NonNull String packageName) throws NameNotFoundException { + throw new UnsupportedOperationException(); + } + + /** * Retrieve all of the information we know about a particular activity * class. * diff --git a/core/java/android/content/pm/ProcessInfo.java b/core/java/android/content/pm/ProcessInfo.java index d45ff98d58e4..3dd5ee102090 100644 --- a/core/java/android/content/pm/ProcessInfo.java +++ b/core/java/android/content/pm/ProcessInfo.java @@ -53,16 +53,30 @@ public class ProcessInfo implements Parcelable { */ public @ApplicationInfo.GwpAsanMode int gwpAsanMode; + /** + * Indicates if the process has requested Memtag to be enabled (in sync or async mode), + * disabled, or left unspecified. + */ + public @ApplicationInfo.MemtagMode int memtagMode; + + /** + * Enable automatic zero-initialization of native heap memory allocations. + */ + @Nullable + public Boolean nativeHeapZeroInit; + @Deprecated public ProcessInfo(@NonNull ProcessInfo orig) { this.name = orig.name; this.deniedPermissions = orig.deniedPermissions; this.gwpAsanMode = orig.gwpAsanMode; + this.memtagMode = orig.memtagMode; + this.nativeHeapZeroInit = orig.nativeHeapZeroInit; } - // Code below generated by codegen v1.0.15. + // Code below generated by codegen v1.0.22. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -84,12 +98,19 @@ public class ProcessInfo implements Parcelable { * If non-null, these are permissions that are not allowed in this process. * @param gwpAsanMode * Indicates if the process has requested GWP-ASan to be enabled, disabled, or left unspecified. + * @param memtagMode + * Indicates if the process has requested Memtag to be enabled (in sync or async mode), + * disabled, or left unspecified. + * @param nativeHeapZeroInit + * Enable automatic zero-initialization of native heap memory allocations. */ @DataClass.Generated.Member public ProcessInfo( @NonNull String name, @Nullable ArraySet<String> deniedPermissions, - @ApplicationInfo.GwpAsanMode int gwpAsanMode) { + @ApplicationInfo.GwpAsanMode int gwpAsanMode, + @ApplicationInfo.MemtagMode int memtagMode, + @Nullable Boolean nativeHeapZeroInit) { this.name = name; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, name); @@ -97,6 +118,10 @@ public class ProcessInfo implements Parcelable { this.gwpAsanMode = gwpAsanMode; com.android.internal.util.AnnotationValidations.validate( ApplicationInfo.GwpAsanMode.class, null, gwpAsanMode); + this.memtagMode = memtagMode; + com.android.internal.util.AnnotationValidations.validate( + ApplicationInfo.MemtagMode.class, null, memtagMode); + this.nativeHeapZeroInit = nativeHeapZeroInit; // onConstructed(); // You can define this method to get a callback } @@ -120,10 +145,13 @@ public class ProcessInfo implements Parcelable { byte flg = 0; if (deniedPermissions != null) flg |= 0x2; + if (nativeHeapZeroInit != null) flg |= 0x10; dest.writeByte(flg); dest.writeString(name); sParcellingForDeniedPermissions.parcel(deniedPermissions, dest, flags); dest.writeInt(gwpAsanMode); + dest.writeInt(memtagMode); + if (nativeHeapZeroInit != null) dest.writeBoolean(nativeHeapZeroInit); } @Override @@ -141,6 +169,8 @@ public class ProcessInfo implements Parcelable { String _name = in.readString(); ArraySet<String> _deniedPermissions = sParcellingForDeniedPermissions.unparcel(in); int _gwpAsanMode = in.readInt(); + int _memtagMode = in.readInt(); + Boolean _nativeHeapZeroInit = (flg & 0x10) == 0 ? null : (Boolean) in.readBoolean(); this.name = _name; com.android.internal.util.AnnotationValidations.validate( @@ -149,6 +179,10 @@ public class ProcessInfo implements Parcelable { this.gwpAsanMode = _gwpAsanMode; com.android.internal.util.AnnotationValidations.validate( ApplicationInfo.GwpAsanMode.class, null, gwpAsanMode); + this.memtagMode = _memtagMode; + com.android.internal.util.AnnotationValidations.validate( + ApplicationInfo.MemtagMode.class, null, memtagMode); + this.nativeHeapZeroInit = _nativeHeapZeroInit; // onConstructed(); // You can define this method to get a callback } @@ -168,10 +202,10 @@ public class ProcessInfo implements Parcelable { }; @DataClass.Generated( - time = 1584555730519L, - codegenVersion = "1.0.15", + time = 1611614699049L, + codegenVersion = "1.0.22", sourceFile = "frameworks/base/core/java/android/content/pm/ProcessInfo.java", - inputSignatures = "public @android.annotation.NonNull java.lang.String name\npublic @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringArraySet.class) android.util.ArraySet<java.lang.String> deniedPermissions\npublic @android.content.pm.ApplicationInfo.GwpAsanMode int gwpAsanMode\nclass ProcessInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)") + inputSignatures = "public @android.annotation.NonNull java.lang.String name\npublic @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringArraySet.class) android.util.ArraySet<java.lang.String> deniedPermissions\npublic @android.content.pm.ApplicationInfo.GwpAsanMode int gwpAsanMode\npublic @android.content.pm.ApplicationInfo.MemtagMode int memtagMode\npublic @android.annotation.Nullable java.lang.Boolean nativeHeapZeroInit\nclass ProcessInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)") @Deprecated private void __metadata() {} diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java index 2ee0ad67b108..983a02ca6576 100644 --- a/core/java/android/content/pm/parsing/ParsingPackage.java +++ b/core/java/android/content/pm/parsing/ParsingPackage.java @@ -241,6 +241,10 @@ public interface ParsingPackage extends ParsingPackageRead { ParsingPackage setGwpAsanMode(int gwpAsanMode); + ParsingPackage setMemtagMode(int memtagMode); + + ParsingPackage setNativeHeapZeroInit(@Nullable Boolean nativeHeapZeroInit); + ParsingPackage setCrossProfile(boolean crossProfile); ParsingPackage setFullBackupContent(int fullBackupContent); diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java index f932bc250e28..ffc78f3fd942 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java +++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java @@ -416,6 +416,11 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { private boolean preserveLegacyExternalStorage; protected int gwpAsanMode; + protected int memtagMode; + + @Nullable + @DataClass.ParcelWith(ForBoolean.class) + private Boolean nativeHeapZeroInit; // TODO(chiuwinson): Non-null @Nullable @@ -926,6 +931,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { appInfo.zygotePreloadName = zygotePreloadName; appInfo.crossProfile = isCrossProfile(); appInfo.setGwpAsanMode(gwpAsanMode); + appInfo.setMemtagMode(memtagMode); + appInfo.setNativeHeapZeroInit(nativeHeapZeroInit); appInfo.setBaseCodePath(baseCodePath); appInfo.setBaseResourcePath(baseCodePath); appInfo.setCodePath(codePath); @@ -1110,6 +1117,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { dest.writeArraySet(this.mimeGroups); dest.writeInt(this.gwpAsanMode); dest.writeSparseIntArray(this.minExtensionVersions); + dest.writeInt(this.memtagMode); + sForBoolean.parcel(this.nativeHeapZeroInit, dest, flags); } public ParsingPackageImpl(Parcel in) { @@ -1270,6 +1279,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { this.mimeGroups = (ArraySet<String>) in.readArraySet(boot); this.gwpAsanMode = in.readInt(); this.minExtensionVersions = in.readSparseIntArray(); + this.memtagMode = in.readInt(); + this.nativeHeapZeroInit = sForBoolean.unparcel(in); } public static final Parcelable.Creator<ParsingPackageImpl> CREATOR = @@ -2003,6 +2014,17 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { } @Override + public int getMemtagMode() { + return memtagMode; + } + + @Nullable + @Override + public Boolean isNativeHeapZeroInit() { + return nativeHeapZeroInit; + } + + @Override public boolean isPartiallyDirectBootAware() { return partiallyDirectBootAware; } @@ -2475,6 +2497,18 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { } @Override + public ParsingPackageImpl setMemtagMode(int value) { + memtagMode = value; + return this; + } + + @Override + public ParsingPackageImpl setNativeHeapZeroInit(@Nullable Boolean value) { + nativeHeapZeroInit = value; + return this; + } + + @Override public ParsingPackageImpl setPartiallyDirectBootAware(boolean value) { partiallyDirectBootAware = value; return this; diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java index 5b53c18b820c..cd91e280b695 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageRead.java +++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java @@ -856,6 +856,19 @@ public interface ParsingPackageRead extends Parcelable { */ public int getGwpAsanMode(); + /** + * @see ApplicationInfo#memtagMode + * @see R.styleable#AndroidManifest_memtagMode + */ + int getMemtagMode(); + + /** + * @see ApplicationInfo#nativeHeapZeroInit + * @see R.styleable#AndroidManifest_nativeHeapZeroInit + */ + @Nullable + Boolean isNativeHeapZeroInit(); + // TODO(b/135203078): Hide and enforce going through PackageInfoUtils ApplicationInfo toAppInfoWithoutState(); diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index ab0ed51fb909..890ba8a59a89 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -1799,6 +1799,11 @@ public class ParsingPackageUtils { } pkg.setGwpAsanMode(sa.getInt(R.styleable.AndroidManifestApplication_gwpAsanMode, -1)); + pkg.setMemtagMode(sa.getInt(R.styleable.AndroidManifestApplication_memtagMode, -1)); + if (sa.hasValue(R.styleable.AndroidManifestApplication_nativeHeapZeroInit)) { + pkg.setNativeHeapZeroInit(sa.getBoolean( + R.styleable.AndroidManifestApplication_nativeHeapZeroInit, false)); + } } finally { sa.recycle(); } diff --git a/core/java/android/content/pm/parsing/component/ParsedProcess.java b/core/java/android/content/pm/parsing/component/ParsedProcess.java index e0ae81b2e30b..89fef9d8e0dd 100644 --- a/core/java/android/content/pm/parsing/component/ParsedProcess.java +++ b/core/java/android/content/pm/parsing/component/ParsedProcess.java @@ -20,6 +20,7 @@ import static java.util.Collections.emptySet; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.pm.ApplicationInfo; import android.os.Parcel; import android.os.Parcelable; import android.util.ArraySet; @@ -41,7 +42,10 @@ public class ParsedProcess implements Parcelable { @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class) protected Set<String> deniedPermissions = emptySet(); - protected int gwpAsanMode = -1; + protected int gwpAsanMode = ApplicationInfo.GWP_ASAN_DEFAULT; + protected int memtagMode = ApplicationInfo.MEMTAG_DEFAULT; + @Nullable + protected Boolean nativeHeapZeroInit = null; public ParsedProcess() { } @@ -57,7 +61,7 @@ public class ParsedProcess implements Parcelable { - // Code below generated by codegen v1.0.15. + // Code below generated by codegen v1.0.22. // // DO NOT MODIFY! // CHECKSTYLE:OFF Generated code @@ -74,7 +78,9 @@ public class ParsedProcess implements Parcelable { public ParsedProcess( @NonNull String name, @NonNull Set<String> deniedPermissions, - int gwpAsanMode) { + int gwpAsanMode, + int memtagMode, + @Nullable Boolean nativeHeapZeroInit) { this.name = name; com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, name); @@ -82,6 +88,8 @@ public class ParsedProcess implements Parcelable { com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, deniedPermissions); this.gwpAsanMode = gwpAsanMode; + this.memtagMode = memtagMode; + this.nativeHeapZeroInit = nativeHeapZeroInit; // onConstructed(); // You can define this method to get a callback } @@ -102,6 +110,16 @@ public class ParsedProcess implements Parcelable { } @DataClass.Generated.Member + public int getMemtagMode() { + return memtagMode; + } + + @DataClass.Generated.Member + public @Nullable Boolean getNativeHeapZeroInit() { + return nativeHeapZeroInit; + } + + @DataClass.Generated.Member static Parcelling<Set<String>> sParcellingForDeniedPermissions = Parcelling.Cache.get( Parcelling.BuiltIn.ForInternedStringSet.class); @@ -118,9 +136,14 @@ public class ParsedProcess implements Parcelable { // You can override field parcelling by defining methods like: // void parcelFieldName(Parcel dest, int flags) { ... } + byte flg = 0; + if (nativeHeapZeroInit != null) flg |= 0x10; + dest.writeByte(flg); dest.writeString(name); sParcellingForDeniedPermissions.parcel(deniedPermissions, dest, flags); dest.writeInt(gwpAsanMode); + dest.writeInt(memtagMode); + if (nativeHeapZeroInit != null) dest.writeBoolean(nativeHeapZeroInit); } @Override @@ -134,9 +157,12 @@ public class ParsedProcess implements Parcelable { // You can override field unparcelling by defining methods like: // static FieldType unparcelFieldName(Parcel in) { ... } + byte flg = in.readByte(); String _name = in.readString(); Set<String> _deniedPermissions = sParcellingForDeniedPermissions.unparcel(in); int _gwpAsanMode = in.readInt(); + int _memtagMode = in.readInt(); + Boolean _nativeHeapZeroInit = (flg & 0x10) == 0 ? null : (Boolean) in.readBoolean(); this.name = _name; com.android.internal.util.AnnotationValidations.validate( @@ -145,6 +171,8 @@ public class ParsedProcess implements Parcelable { com.android.internal.util.AnnotationValidations.validate( NonNull.class, null, deniedPermissions); this.gwpAsanMode = _gwpAsanMode; + this.memtagMode = _memtagMode; + this.nativeHeapZeroInit = _nativeHeapZeroInit; // onConstructed(); // You can define this method to get a callback } @@ -164,10 +192,10 @@ public class ParsedProcess implements Parcelable { }; @DataClass.Generated( - time = 1584557524776L, - codegenVersion = "1.0.15", + time = 1611615591258L, + codegenVersion = "1.0.22", sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcess.java", - inputSignatures = "protected @android.annotation.NonNull java.lang.String name\nprotected @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set<java.lang.String> deniedPermissions\nprotected int gwpAsanMode\npublic void addStateFrom(android.content.pm.parsing.component.ParsedProcess)\nclass ParsedProcess extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)") + inputSignatures = "protected @android.annotation.NonNull java.lang.String name\nprotected @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set<java.lang.String> deniedPermissions\nprotected int gwpAsanMode\nprotected int memtagMode\nprotected @android.annotation.Nullable java.lang.Boolean nativeHeapZeroInit\npublic void addStateFrom(android.content.pm.parsing.component.ParsedProcess)\nclass ParsedProcess extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)") @Deprecated private void __metadata() {} diff --git a/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java index 837270721078..082593efd498 100644 --- a/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java +++ b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java @@ -105,6 +105,11 @@ public class ParsedProcessUtils { } proc.gwpAsanMode = sa.getInt(R.styleable.AndroidManifestProcess_gwpAsanMode, -1); + proc.memtagMode = sa.getInt(R.styleable.AndroidManifestProcess_memtagMode, -1); + if (sa.hasValue(R.styleable.AndroidManifestProcess_nativeHeapZeroInit)) { + proc.nativeHeapZeroInit = + sa.getBoolean(R.styleable.AndroidManifestProcess_nativeHeapZeroInit, false); + } } finally { sa.recycle(); } diff --git a/core/java/android/content/pm/verify/domain/OWNERS b/core/java/android/content/pm/verify/domain/OWNERS new file mode 100644 index 000000000000..c669112e0512 --- /dev/null +++ b/core/java/android/content/pm/verify/domain/OWNERS @@ -0,0 +1,5 @@ +# Bug component: 36137 + +chiuwinson@google.com +patb@google.com +toddke@google.com
\ No newline at end of file diff --git a/core/java/android/hardware/soundtrigger/OWNERS b/core/java/android/hardware/soundtrigger/OWNERS index 816bc6bba639..e5d037003ac4 100644 --- a/core/java/android/hardware/soundtrigger/OWNERS +++ b/core/java/android/hardware/soundtrigger/OWNERS @@ -1 +1,2 @@ -include /core/java/android/media/soundtrigger/OWNERS +ytai@google.com +elaurent@google.com diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 32b19a462218..303a40755d4e 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -18,6 +18,7 @@ package android.net; import static android.net.ConnectivityManager.TYPE_WIFI; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.wifi.WifiInfo; @@ -41,6 +42,22 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { public static final int SUBTYPE_COMBINED = -1; + /** + * Network has no {@code NetworkCapabilities#NET_CAPABILITY_OEM_*}. + * @hide + */ + public static final int OEM_NONE = 0x0; + /** + * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}. + * @hide + */ + public static final int OEM_PAID = 0x1; + /** + * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}. + * @hide + */ + public static final int OEM_PRIVATE = 0x2; + final int mType; final int mSubType; final String mSubscriberId; @@ -48,10 +65,11 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { final boolean mRoaming; final boolean mMetered; final boolean mDefaultNetwork; + final int mOemManaged; public NetworkIdentity( int type, int subType, String subscriberId, String networkId, boolean roaming, - boolean metered, boolean defaultNetwork) { + boolean metered, boolean defaultNetwork, int oemManaged) { mType = type; mSubType = subType; mSubscriberId = subscriberId; @@ -59,12 +77,13 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { mRoaming = roaming; mMetered = metered; mDefaultNetwork = defaultNetwork; + mOemManaged = oemManaged; } @Override public int hashCode() { return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming, mMetered, - mDefaultNetwork); + mDefaultNetwork, mOemManaged); } @Override @@ -75,7 +94,8 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { && Objects.equals(mSubscriberId, ident.mSubscriberId) && Objects.equals(mNetworkId, ident.mNetworkId) && mMetered == ident.mMetered - && mDefaultNetwork == ident.mDefaultNetwork; + && mDefaultNetwork == ident.mDefaultNetwork + && mOemManaged == ident.mOemManaged; } return false; } @@ -102,6 +122,8 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { } builder.append(", metered=").append(mMetered); builder.append(", defaultNetwork=").append(mDefaultNetwork); + // TODO(180557699): Print a human readable string for OEM managed state. + builder.append(", oemManaged=").append(mOemManaged); return builder.append("}").toString(); } @@ -120,6 +142,7 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { proto.write(NetworkIdentityProto.ROAMING, mRoaming); proto.write(NetworkIdentityProto.METERED, mMetered); proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork); + proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged); proto.end(start); } @@ -152,6 +175,10 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { return mDefaultNetwork; } + public int getOemManaged() { + return mOemManaged; + } + /** * Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType}, * assuming that any mobile networks are using the current IMSI. The subType if applicable, @@ -171,6 +198,8 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { subscriberId = state.subscriberId; + final int oemManaged = getOemBitfield(state.networkCapabilities); + if (legacyType == TYPE_WIFI) { if (state.networkCapabilities.getSsid() != null) { networkId = state.networkCapabilities.getSsid(); @@ -185,7 +214,24 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { } return new NetworkIdentity(legacyType, subType, subscriberId, networkId, roaming, metered, - defaultNetwork); + defaultNetwork, oemManaged); + } + + /** + * Builds a bitfield of {@code NetworkIdentity.OEM_*} based on {@link NetworkCapabilities}. + * @hide + */ + public static int getOemBitfield(NetworkCapabilities nc) { + int oemManaged = OEM_NONE; + + if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID)) { + oemManaged |= OEM_PAID; + } + if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE)) { + oemManaged |= OEM_PRIVATE; + } + + return oemManaged; } @Override @@ -209,6 +255,9 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> { if (res == 0) { res = Boolean.compare(mDefaultNetwork, another.mDefaultNetwork); } + if (res == 0) { + res = Integer.compare(mOemManaged, another.mOemManaged); + } return res; } } diff --git a/core/java/android/net/NetworkStateSnapshot.aidl b/core/java/android/net/NetworkStateSnapshot.aidl new file mode 100644 index 000000000000..cb602d7927ce --- /dev/null +++ b/core/java/android/net/NetworkStateSnapshot.aidl @@ -0,0 +1,19 @@ +/** + * 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.net; + +parcelable NetworkStateSnapshot; diff --git a/core/java/android/net/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java new file mode 100644 index 000000000000..881b373fa241 --- /dev/null +++ b/core/java/android/net/NetworkStateSnapshot.java @@ -0,0 +1,106 @@ +/* + * 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.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Snapshot of network state. + * + * @hide + */ +public final class NetworkStateSnapshot implements Parcelable { + @NonNull + public final LinkProperties linkProperties; + @NonNull + public final NetworkCapabilities networkCapabilities; + @NonNull + public final Network network; + @Nullable + public final String subscriberId; + public final int legacyType; + + public NetworkStateSnapshot(@NonNull LinkProperties linkProperties, + @NonNull NetworkCapabilities networkCapabilities, @NonNull Network network, + @Nullable String subscriberId, int legacyType) { + this.linkProperties = Objects.requireNonNull(linkProperties); + this.networkCapabilities = Objects.requireNonNull(networkCapabilities); + this.network = Objects.requireNonNull(network); + this.subscriberId = subscriberId; + this.legacyType = legacyType; + } + + public NetworkStateSnapshot(@NonNull Parcel in) { + linkProperties = in.readParcelable(null); + networkCapabilities = in.readParcelable(null); + network = in.readParcelable(null); + subscriberId = in.readString(); + legacyType = in.readInt(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeParcelable(linkProperties, flags); + out.writeParcelable(networkCapabilities, flags); + out.writeParcelable(network, flags); + out.writeString(subscriberId); + out.writeInt(legacyType); + } + + @NonNull + public static final Creator<NetworkStateSnapshot> CREATOR = + new Creator<NetworkStateSnapshot>() { + @NonNull + @Override + public NetworkStateSnapshot createFromParcel(@NonNull Parcel in) { + return new NetworkStateSnapshot(in); + } + + @NonNull + @Override + public NetworkStateSnapshot[] newArray(int size) { + return new NetworkStateSnapshot[size]; + } + }; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof NetworkStateSnapshot)) return false; + NetworkStateSnapshot that = (NetworkStateSnapshot) o; + return legacyType == that.legacyType + && Objects.equals(linkProperties, that.linkProperties) + && Objects.equals(networkCapabilities, that.networkCapabilities) + && Objects.equals(network, that.network) + && Objects.equals(subscriberId, that.subscriberId); + } + + @Override + public int hashCode() { + return Objects.hash(linkProperties, networkCapabilities, network, subscriberId, legacyType); + } +} diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index aa61e03b285c..c83dd99c2a3b 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -23,6 +23,7 @@ import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; +import static android.net.NetworkIdentity.OEM_NONE; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.DEFAULT_NETWORK_YES; @@ -99,6 +100,22 @@ public class NetworkTemplate implements Parcelable { */ public static final int NETWORK_TYPE_5G_NSA = -2; + /** + * Value to match both OEM managed and unmanaged networks (all networks). + * @hide + */ + public static final int OEM_MANAGED_ALL = -1; + /** + * Value to match networks which are not OEM managed. + * @hide + */ + public static final int OEM_MANAGED_NO = OEM_NONE; + /** + * Value to match any OEM managed network. + * @hide + */ + public static final int OEM_MANAGED_YES = -2; + private static boolean isKnownMatchRule(final int rule) { switch (rule) { case MATCH_MOBILE: @@ -151,10 +168,10 @@ public class NetworkTemplate implements Parcelable { @NetworkType int ratType) { if (TextUtils.isEmpty(subscriberId)) { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL); } return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL); } /** @@ -235,6 +252,9 @@ public class NetworkTemplate implements Parcelable { private final int mDefaultNetwork; private final int mSubType; + // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}. + private final int mOemManaged; + @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); @@ -243,11 +263,12 @@ public class NetworkTemplate implements Parcelable { public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL); + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL); } public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, - String networkId, int metered, int roaming, int defaultNetwork, int subType) { + String networkId, int metered, int roaming, int defaultNetwork, int subType, + int oemManaged) { mMatchRule = matchRule; mSubscriberId = subscriberId; mMatchSubscriberIds = matchSubscriberIds; @@ -256,6 +277,7 @@ public class NetworkTemplate implements Parcelable { mRoaming = roaming; mDefaultNetwork = defaultNetwork; mSubType = subType; + mOemManaged = oemManaged; if (!isKnownMatchRule(matchRule)) { Log.e(TAG, "Unknown network template rule " + matchRule @@ -272,6 +294,7 @@ public class NetworkTemplate implements Parcelable { mRoaming = in.readInt(); mDefaultNetwork = in.readInt(); mSubType = in.readInt(); + mOemManaged = in.readInt(); } @Override @@ -284,6 +307,7 @@ public class NetworkTemplate implements Parcelable { dest.writeInt(mRoaming); dest.writeInt(mDefaultNetwork); dest.writeInt(mSubType); + dest.writeInt(mOemManaged); } @Override @@ -319,13 +343,16 @@ public class NetworkTemplate implements Parcelable { if (mSubType != NETWORK_TYPE_ALL) { builder.append(", subType=").append(mSubType); } + if (mOemManaged != OEM_MANAGED_ALL) { + builder.append(", oemManaged=").append(mOemManaged); + } return builder.toString(); } @Override public int hashCode() { return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming, - mDefaultNetwork, mSubType); + mDefaultNetwork, mSubType, mOemManaged); } @Override @@ -338,7 +365,8 @@ public class NetworkTemplate implements Parcelable { && mMetered == other.mMetered && mRoaming == other.mRoaming && mDefaultNetwork == other.mDefaultNetwork - && mSubType == other.mSubType; + && mSubType == other.mSubType + && mOemManaged == other.mOemManaged; } return false; } @@ -384,6 +412,7 @@ public class NetworkTemplate implements Parcelable { if (!matchesMetered(ident)) return false; if (!matchesRoaming(ident)) return false; if (!matchesDefaultNetwork(ident)) return false; + if (!matchesOemNetwork(ident)) return false; switch (mMatchRule) { case MATCH_MOBILE: @@ -425,6 +454,13 @@ public class NetworkTemplate implements Parcelable { || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork); } + private boolean matchesOemNetwork(NetworkIdentity ident) { + return (mOemManaged == OEM_MANAGED_ALL) + || (mOemManaged == OEM_MANAGED_YES + && ident.mOemManaged != OEM_NONE) + || (mOemManaged == ident.mOemManaged); + } + private boolean matchesCollapsedRatType(NetworkIdentity ident) { return mSubType == NETWORK_TYPE_ALL || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType); diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java index b172ccc4e370..f0e7da78d669 100644 --- a/core/java/android/net/UidRange.java +++ b/core/java/android/net/UidRange.java @@ -42,10 +42,6 @@ public final class UidRange implements Parcelable { stop = stopUid; } - public static UidRange createForUser(int userId) { - return new UidRange(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1); - } - /** Creates a UidRange for the specified user. */ public static UidRange createForUser(UserHandle user) { final UserHandle nextUser = UserHandle.of(user.getIdentifier() + 1); diff --git a/core/java/android/net/vcn/IVcnStatusCallback.aidl b/core/java/android/net/vcn/IVcnStatusCallback.aidl index 555e9b5883e8..d91cef592d10 100644 --- a/core/java/android/net/vcn/IVcnStatusCallback.aidl +++ b/core/java/android/net/vcn/IVcnStatusCallback.aidl @@ -17,8 +17,9 @@ package android.net.vcn; /** @hide */ -interface IVcnStatusCallback { +oneway interface IVcnStatusCallback { void onEnteredSafeMode(); + void onVcnStatusChanged(int statusCode); void onGatewayConnectionError( in int[] gatewayNetworkCapabilities, int errorCode, diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java index 729e68a6a911..eb8c251fec78 100644 --- a/core/java/android/net/vcn/VcnManager.java +++ b/core/java/android/net/vcn/VcnManager.java @@ -349,6 +349,56 @@ public class VcnManager { /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef({ + VCN_STATUS_CODE_NOT_CONFIGURED, + VCN_STATUS_CODE_INACTIVE, + VCN_STATUS_CODE_ACTIVE, + VCN_STATUS_CODE_SAFE_MODE + }) + public @interface VcnStatusCode {} + + /** + * Value indicating that the VCN for the subscription group is not configured, or that the + * callback is not privileged for the subscription group. + * + * @hide + */ + public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0; + + /** + * Value indicating that the VCN for the subscription group is inactive. + * + * <p>A VCN is inactive if a {@link VcnConfig} is present for the subscription group, but the + * provisioning package is not privileged. + * + * @hide + */ + public static final int VCN_STATUS_CODE_INACTIVE = 1; + + /** + * Value indicating that the VCN for the subscription group is active. + * + * <p>A VCN is active if a {@link VcnConfig} is present for the subscription, the provisioning + * package is privileged, and the VCN is not in Safe Mode. In other words, a VCN is considered + * active while it is connecting, fully connected, and disconnecting. + * + * @hide + */ + public static final int VCN_STATUS_CODE_ACTIVE = 2; + + /** + * Value indicating that the VCN for the subscription group is in Safe Mode. + * + * <p>A VCN will be put into Safe Mode if any of the gateway connections were unable to + * establish a connection within a system-determined timeout (while underlying networks were + * available). + * + * @hide + */ + public static final int VCN_STATUS_CODE_SAFE_MODE = 3; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ VCN_ERROR_CODE_INTERNAL_ERROR, VCN_ERROR_CODE_CONFIG_ERROR, VCN_ERROR_CODE_NETWORK_ERROR @@ -403,8 +453,18 @@ public class VcnManager { * * <p>A VCN-configuring app may opt to exit safe mode by (re)setting the VCN configuration * via {@link #setVcnConfig(ParcelUuid, VcnConfig)}. + * + * @hide */ - public abstract void onEnteredSafeMode(); + public void onEnteredSafeMode() {} + + /** + * Invoked when status of the VCN for this callback's subscription group changes. + * + * @param statusCode the code for the status change encountered by this {@link + * VcnStatusCallback}'s subscription group. + */ + public abstract void onVcnStatusChanged(@VcnStatusCode int statusCode); /** * Invoked when a VCN Gateway Connection corresponding to this callback's subscription @@ -436,6 +496,11 @@ public class VcnManager { * <p>A {@link VcnStatusCallback} will only be invoked if the registering package has carrier * privileges for the specified subscription at the time of invocation. * + * <p>{@link VcnStatusCallback#onVcnStatusChanged(int)} will be invoked on registration with the + * current status for the specified subscription group's VCN. If the registrant is not + * privileged for this subscription group, {@link #VCN_STATUS_CODE_NOT_CONFIGURED} will be + * returned. + * * @param subscriptionGroup The subscription group to match for callbacks * @param executor The {@link Executor} to be used for invoking callbacks * @param callback The VcnStatusCallback to be registered @@ -539,6 +604,12 @@ public class VcnManager { () -> mExecutor.execute(() -> mCallback.onEnteredSafeMode())); } + @Override + public void onVcnStatusChanged(@VcnStatusCode int statusCode) { + Binder.withCleanCallingIdentity( + () -> mExecutor.execute(() -> mCallback.onVcnStatusChanged(statusCode))); + } + // TODO(b/180521637): use ServiceSpecificException for safer Exception 'parceling' @Override public void onGatewayConnectionError( diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java index a435ac12d33c..73bb8d566500 100644 --- a/core/java/android/os/BugreportManager.java +++ b/core/java/android/os/BugreportManager.java @@ -68,8 +68,11 @@ public final class BugreportManager { /** * An interface describing the callback for bugreport progress and status. * - * <p>In general, callers can expect to receive {@link #onProgress} calls as the bugreport - * progresses, followed by a terminal call to either {@link #onFinished} or {@link #onError}. + * <p>Callers will receive {@link #onProgress} calls as the bugreport progresses, followed by a + * terminal call to either {@link #onFinished} or {@link #onError}. + * + * <p>If an issue is encountered while starting the bugreport asynchronously, callers will + * receive an {@link #onError} call without any {@link #onProgress} callbacks. */ public abstract static class BugreportCallback { /** diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java index b1014af3122e..336045990af7 100644 --- a/core/java/android/os/SystemClock.java +++ b/core/java/android/os/SystemClock.java @@ -329,8 +329,7 @@ public final class SystemClock { try { time = mMgr.getGnssTimeMillis(); } catch (RemoteException e) { - e.rethrowFromSystemServer(); - return 0; + throw e.rethrowFromSystemServer(); } if (time == null) { throw new DateTimeException("Gnss based time is not available."); diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 9e332e9b0456..c9da6418471d 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -426,7 +426,7 @@ public class ZygoteProcess { // avoid writing a partial response to the zygote. for (String arg : args) { // Making two indexOf calls here is faster than running a manually fused loop due - // to the fact that indexOf is a optimized intrinsic. + // to the fact that indexOf is an optimized intrinsic. if (arg.indexOf('\n') >= 0) { throw new ZygoteStartFailedEx("Embedded newlines not allowed"); } else if (arg.indexOf('\r') >= 0) { diff --git a/core/java/android/provider/SimPhonebookContract.java b/core/java/android/provider/SimPhonebookContract.java index 074d5f167ec3..030b86339822 100644 --- a/core/java/android/provider/SimPhonebookContract.java +++ b/core/java/android/provider/SimPhonebookContract.java @@ -44,8 +44,11 @@ import java.util.Objects; * The contract between the provider of contact records on the device's SIM cards and applications. * Contains definitions of the supported URIs and columns. * - * <p>This content provider does not support any of the QUERY_ARG_SQL* bundle arguments. An - * IllegalArgumentException will be thrown if these are included. + * <h3>Permissions</h3> + * <p> + * Querying this provider requires {@link android.Manifest.permission#READ_CONTACTS} and writing + * to this provider requires {@link android.Manifest.permission#WRITE_CONTACTS} + * </p> */ public final class SimPhonebookContract { @@ -85,7 +88,73 @@ public final class SimPhonebookContract { } } - /** Constants for the contact records on a SIM card. */ + /** + * Constants for the contact records on a SIM card. + * + * <h3 id="simrecords-data">Data</h3> + * <p> + * Data is stored in a specific elementary file on a specific SIM card and these are isolated + * from each other. SIM cards are identified by their subscription ID. SIM cards may not support + * all or even any of the elementary file types. A SIM will have constraints on + * the values of the data that can be stored in each elementary file. The available SIMs, + * their supported elementary file types and the constraints on the data can be discovered by + * querying {@link ElementaryFiles#CONTENT_URI}. Each elementary file has a fixed capacity + * for the number of records that may be stored. This can be determined from the value + * of the {@link ElementaryFiles#MAX_RECORDS} column. + * </p> + * <p> + * The {@link SimRecords#PHONE_NUMBER} column can only contain dialable characters and this + * applies regardless of the SIM that is being used. See + * {@link android.telephony.PhoneNumberUtils#isDialable(char)} for more details. Additionally + * the phone number can contain at most {@link ElementaryFiles#PHONE_NUMBER_MAX_LENGTH} + * characters. The {@link SimRecords#NAME} column can contain at most + * {@link ElementaryFiles#NAME_MAX_LENGTH} bytes when it is encoded for storage on the SIM. + * Encoding is done internally and so the name should be provided unencoded but the number of + * bytes required to encode it will vary depending on the characters it contains. This length + * can be determined by calling + * {@link SimRecords#getEncodedNameLength(ContentResolver, String)}. + * </p> + * <h3>Operations </h3> + * <dl> + * <dd><b>Insert</b></dd> + * <p> + * Only {@link ElementaryFiles#EF_ADN} supports inserts. {@link SimRecords#PHONE_NUMBER} + * is a required column. If the value provided for this column is missing, null, empty + * or violates the requirements discussed in the <a href="#simrecords-data">Data</a> + * section above an {@link IllegalArgumentException} will be thrown. The + * {@link SimRecords#NAME} column may be omitted but if provided and it violates any of + * the requirements discussed in the <a href="#simrecords-data">Data</a> section above + * an {@link IllegalArgumentException} will be thrown. + * </p> + * <p> + * If an insert is not possible because the elementary file is full then an + * {@link IllegalStateException} will be thrown. + * </p> + * <dd><b>Update</b></dd> + * <p> + * Updates can only be performed for individual records on {@link ElementaryFiles#EF_ADN}. + * A specific record is referenced via the Uri returned by + * {@link SimRecords#getItemUri(int, int, int)}. Updates have the same constraints and + * behavior for the {@link SimRecords#PHONE_NUMBER} and {@link SimRecords#NAME} as insert. + * However, in the case of update the {@link SimRecords#PHONE_NUMBER} may be omitted as + * the existing record will already have a valid value. + * </p> + * <dd><b>Delete</b></dd> + * <p> + * Delete may only be performed for individual records on {@link ElementaryFiles#EF_ADN}. + * Deleting records will free up space for use by future inserts. + * </p> + * <dd><b>Query</b></dd> + * <p> + * All the records stored on a specific elementary file can be read via a Uri returned by + * {@link SimRecords#getContentUri(int, int)}. This query always returns all records; there + * is no support for filtering via a selection. An individual record can be queried via a Uri + * returned by {@link SimRecords#getItemUri(int, int, int)}. Queries will throw an + * {@link IllegalArgumentException} when the SIM with the subscription ID or the elementary file + * type are invalid or unavailable. + * </p> + * </dl> + */ public static final class SimRecords { /** @@ -197,8 +266,8 @@ public final class SimPhonebookContract { * be discovered by querying {@link ElementaryFiles#CONTENT_URI}. * * <p>If a SIM with the provided subscription ID does not exist or the SIM with the provided - * subscription ID doesn't support the specified entity file then queries will return - * and empty cursor and inserts will throw an {@link IllegalArgumentException} + * subscription ID doesn't support the specified entity file then all operations will + * throw an {@link IllegalArgumentException}. * * @param subscriptionId the subscriptionId of the SIM card that this Uri will reference * @param efType the elementary file on the SIM that this Uri will reference @@ -233,6 +302,9 @@ public final class SimPhonebookContract { * must be greater than 0. If there is no record with this record * number in the specified entity file then it will be treated as a * non-existent record. + * @see ElementaryFiles#SUBSCRIPTION_ID + * @see ElementaryFiles#EF_TYPE + * @see #RECORD_NUMBER */ @NonNull public static Uri getItemUri( @@ -287,7 +359,28 @@ public final class SimPhonebookContract { } - /** Constants for metadata about the elementary files of the SIM cards in the phone. */ + /** + * Constants for metadata about the elementary files of the SIM cards in the phone. + * + * <h3>Operations </h3> + * <dl> + * <dd><b>Insert</b></dd> + * <p>Insert is not supported for the Uris defined in this class.</p> + * <dd><b>Update</b></dd> + * <p>Update is not supported for the Uris defined in this class.</p> + * <dd><b>Delete</b></dd> + * <p>Delete is not supported for the Uris defined in this class.</p> + * <dd><b>Query</b></dd> + * <p> + * The elementary files for all the inserted SIMs can be read via + * {@link ElementaryFiles#CONTENT_URI}. Unsupported elementary files are omitted from the + * results. This Uri always returns all supported elementary files for all available SIMs; it + * does not support filtering via a selection. A specific elementary file can be queried + * via a Uri returned by {@link ElementaryFiles#getItemUri(int, int)}. If the elementary file + * referenced by this Uri is unsupported by the SIM then the query will return an empty cursor. + * </p> + * </dl> + */ public static final class ElementaryFiles { /** {@link SubscriptionInfo#getSimSlotIndex()} of the SIM for this row. */ diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java index cc3e57859b64..1dc7f71fbb0e 100644 --- a/core/java/android/security/keystore/recovery/RecoveryController.java +++ b/core/java/android/security/keystore/recovery/RecoveryController.java @@ -27,8 +27,11 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.security.KeyStore; -import android.security.keystore.AndroidKeyStoreProvider; +import android.security.KeyStore2; import android.security.keystore.KeyPermanentlyInvalidatedException; +import android.security.keystore2.AndroidKeyStoreProvider; +import android.system.keystore2.Domain; +import android.system.keystore2.KeyDescriptor; import com.android.internal.widget.ILockSettings; @@ -709,10 +712,34 @@ public class RecoveryController { */ @NonNull Key getKeyFromGrant(@NonNull String grantAlias) throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { - return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore( - mKeyStore, - grantAlias, - KeyStore.UID_SELF); + if (grantAlias.startsWith(APPLICATION_KEY_GRANT_PREFIX)) { + return AndroidKeyStoreProvider + .loadAndroidKeyStoreSecretKeyFromKeystore( + KeyStore2.getInstance(), + getGrantDescriptor(grantAlias)); + } + // TODO(b/171305545): remove KeyStore1 logic. + return android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore( + mKeyStore, + grantAlias, + KeyStore.UID_SELF); + + } + + private static final String APPLICATION_KEY_GRANT_PREFIX = "recoverable_key:"; + + private static @Nullable KeyDescriptor getGrantDescriptor(String grantAlias) { + KeyDescriptor result = new KeyDescriptor(); + result.domain = Domain.GRANT; + result.blob = null; + result.alias = null; + try { + result.nspace = Long.parseUnsignedLong( + grantAlias.substring(APPLICATION_KEY_GRANT_PREFIX.length()), 16); + } catch (NumberFormatException e) { + return null; + } + return result; } /** diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index a9548b0a42b4..299a292936ae 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -332,12 +332,12 @@ public class TelephonyRegistryManager { /** * Notify {@link ServiceState} update on certain subscription. * - * @param subId for which the service state changed. * @param slotIndex for which the service state changed. Can be derived from subId except * subId is invalid. + * @param subId for which the service state changed. * @param state service state e.g, in service, out of service or roaming status. */ - public void notifyServiceStateChanged(int subId, int slotIndex, @NonNull ServiceState state) { + public void notifyServiceStateChanged(int slotIndex, int subId, @NonNull ServiceState state) { try { sRegistry.notifyServiceStateForPhoneId(slotIndex, subId, state); } catch (RemoteException ex) { @@ -348,12 +348,12 @@ public class TelephonyRegistryManager { /** * Notify {@link SignalStrength} update on certain subscription. * - * @param subId for which the signalstrength changed. * @param slotIndex for which the signalstrength changed. Can be derived from subId except when * subId is invalid. + * @param subId for which the signalstrength changed. * @param signalStrength e.g, signalstrength level {@see SignalStrength#getLevel()} */ - public void notifySignalStrengthChanged(int subId, int slotIndex, + public void notifySignalStrengthChanged(int slotIndex, int subId, @NonNull SignalStrength signalStrength) { try { sRegistry.notifySignalStrengthForPhoneId(slotIndex, subId, signalStrength); @@ -366,13 +366,13 @@ public class TelephonyRegistryManager { * Notify changes to the message-waiting indicator on certain subscription. e.g, The status bar * uses message waiting indicator to determine when to display the voicemail icon. * - * @param subId for which message waiting indicator changed. * @param slotIndex for which message waiting indicator changed. Can be derived from subId * except when subId is invalid. + * @param subId for which message waiting indicator changed. * @param msgWaitingInd {@code true} indicates there is message-waiting indicator, {@code false} * otherwise. */ - public void notifyMessageWaitingChanged(int subId, int slotIndex, boolean msgWaitingInd) { + public void notifyMessageWaitingChanged(int slotIndex, int subId, boolean msgWaitingInd) { try { sRegistry.notifyMessageWaitingChangedForPhoneId(slotIndex, subId, msgWaitingInd); } catch (RemoteException ex) { @@ -413,9 +413,9 @@ public class TelephonyRegistryManager { /** * Notify changes to default (Internet) data connection state on certain subscription. * - * @param subId for which data connection state changed. * @param slotIndex for which data connections state changed. Can be derived from subId except * when subId is invalid. + * @param subId for which data connection state changed. * @param preciseState the PreciseDataConnectionState * * @see PreciseDataConnectionState @@ -434,13 +434,13 @@ public class TelephonyRegistryManager { /** * Notify {@link CallQuality} change on certain subscription. * - * @param subId for which call quality state changed. * @param slotIndex for which call quality state changed. Can be derived from subId except when * subId is invalid. + * @param subId for which call quality state changed. * @param callQuality Information about call quality e.g, call quality level * @param networkType associated with this data connection. e.g, LTE */ - public void notifyCallQualityChanged(int subId, int slotIndex, @NonNull CallQuality callQuality, + public void notifyCallQualityChanged(int slotIndex, int subId, @NonNull CallQuality callQuality, @NetworkType int networkType) { try { sRegistry.notifyCallQualityChanged(callQuality, slotIndex, subId, networkType); @@ -452,11 +452,11 @@ public class TelephonyRegistryManager { /** * Notify emergency number list changed on certain subscription. * - * @param subId for which emergency number list changed. * @param slotIndex for which emergency number list changed. Can be derived from subId except * when subId is invalid. + * @param subId for which emergency number list changed. */ - public void notifyEmergencyNumberList(int subId, int slotIndex) { + public void notifyEmergencyNumberList( int slotIndex, int subId) { try { sRegistry.notifyEmergencyNumberList(slotIndex, subId); } catch (RemoteException ex) { @@ -497,13 +497,13 @@ public class TelephonyRegistryManager { /** * Notify radio power state changed on certain subscription. * - * @param subId for which radio power state changed. * @param slotIndex for which radio power state changed. Can be derived from subId except when * subId is invalid. + * @param subId for which radio power state changed. * @param radioPowerState the current modem radio state. */ - public void notifyRadioPowerStateChanged(int subId, int slotIndex, - @RadioPowerState int radioPowerState) { + public void notifyRadioPowerStateChanged(int slotIndex, int subId, + @RadioPowerState int radioPowerState) { try { sRegistry.notifyRadioPowerStateChanged(slotIndex, subId, radioPowerState); } catch (RemoteException ex) { @@ -541,13 +541,13 @@ public class TelephonyRegistryManager { * Notify data activation state changed on certain subscription. * @see TelephonyManager#getDataActivationState() * - * @param subId for which data activation state changed. * @param slotIndex for which data activation state changed. Can be derived from subId except * when subId is invalid. + * @param subId for which data activation state changed. * @param activationState sim activation state e.g, activated. */ - public void notifyDataActivationStateChanged(int subId, int slotIndex, - @SimActivationState int activationState) { + public void notifyDataActivationStateChanged(int slotIndex, int subId, + @SimActivationState int activationState) { try { sRegistry.notifySimActivationStateChangedForPhoneId(slotIndex, subId, SIM_ACTIVATION_TYPE_DATA, activationState); @@ -560,13 +560,13 @@ public class TelephonyRegistryManager { * Notify voice activation state changed on certain subscription. * @see TelephonyManager#getVoiceActivationState() * - * @param subId for which voice activation state changed. * @param slotIndex for which voice activation state changed. Can be derived from subId except * subId is invalid. + * @param subId for which voice activation state changed. * @param activationState sim activation state e.g, activated. */ - public void notifyVoiceActivationStateChanged(int subId, int slotIndex, - @SimActivationState int activationState) { + public void notifyVoiceActivationStateChanged(int slotIndex, int subId, + @SimActivationState int activationState) { try { sRegistry.notifySimActivationStateChangedForPhoneId(slotIndex, subId, SIM_ACTIVATION_TYPE_VOICE, activationState); @@ -579,9 +579,9 @@ public class TelephonyRegistryManager { * Notify User mobile data state changed on certain subscription. e.g, mobile data is enabled * or disabled. * - * @param subId for which mobile data state has changed. * @param slotIndex for which mobile data state has changed. Can be derived from subId except * when subId is invalid. + * @param subId for which mobile data state has changed. * @param state {@code true} indicates mobile data is enabled/on. {@code false} otherwise. */ public void notifyUserMobileDataStateChanged(int slotIndex, int subId, boolean state) { @@ -602,7 +602,7 @@ public class TelephonyRegistryManager { * @param telephonyDisplayInfo The display info. */ public void notifyDisplayInfoChanged(int slotIndex, int subscriptionId, - @NonNull TelephonyDisplayInfo telephonyDisplayInfo) { + @NonNull TelephonyDisplayInfo telephonyDisplayInfo) { try { sRegistry.notifyDisplayInfoChanged(slotIndex, subscriptionId, telephonyDisplayInfo); } catch (RemoteException ex) { @@ -643,14 +643,14 @@ public class TelephonyRegistryManager { * Notify precise call state changed on certain subscription, including foreground, background * and ringcall states. * - * @param subId for which precise call state changed. * @param slotIndex for which precise call state changed. Can be derived from subId except when * subId is invalid. + * @param subId for which precise call state changed. * @param ringCallPreciseState ringCall state. * @param foregroundCallPreciseState foreground call state. * @param backgroundCallPreciseState background call state. */ - public void notifyPreciseCallState(int subId, int slotIndex, + public void notifyPreciseCallState(int slotIndex, int subId, @PreciseCallStates int ringCallPreciseState, @PreciseCallStates int foregroundCallPreciseState, @PreciseCallStates int backgroundCallPreciseState) { @@ -793,9 +793,10 @@ public class TelephonyRegistryManager { * @param reason Reason for data enabled/disabled. See {@code REASON_*} in * {@link TelephonyManager}. */ - public void notifyDataEnabled(boolean enabled, @TelephonyManager.DataEnabledReason int reason) { + public void notifyDataEnabled(int slotIndex, int subId, boolean enabled, + @TelephonyManager.DataEnabledReason int reason) { try { - sRegistry.notifyDataEnabled(enabled, reason); + sRegistry.notifyDataEnabled(slotIndex, subId, enabled, reason); } catch (RemoteException ex) { // system server crash } diff --git a/core/java/android/uwb/AngleOfArrivalSupport.aidl b/core/java/android/uwb/AngleOfArrivalSupport.aidl deleted file mode 100644 index 57666ff8bca9..000000000000 --- a/core/java/android/uwb/AngleOfArrivalSupport.aidl +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.uwb; - -/** - * @hide - */ -@Backing(type="int") -enum AngleOfArrivalSupport { - /** - * The device does not support angle of arrival - */ - NONE, - - /** - * The device supports planar angle of arrival - */ - TWO_DIMENSIONAL, - - /** - * The device does supports three dimensional angle of arrival with hemispherical azimuth angles - */ - THREE_DIMENSIONAL_HEMISPHERICAL, - - /** - * The device does supports three dimensional angle of arrival with full azimuth angles - */ - THREE_DIMENSIONAL_SPHERICAL, -} - diff --git a/core/java/android/uwb/IUwbAdapter.aidl b/core/java/android/uwb/IUwbAdapter.aidl index b9c55081a103..468a69c7bddb 100644 --- a/core/java/android/uwb/IUwbAdapter.aidl +++ b/core/java/android/uwb/IUwbAdapter.aidl @@ -17,7 +17,6 @@ package android.uwb; import android.os.PersistableBundle; -import android.uwb.AngleOfArrivalSupport; import android.uwb.IUwbAdapterStateCallbacks; import android.uwb.IUwbRangingCallbacks; import android.uwb.SessionHandle; @@ -47,43 +46,6 @@ interface IUwbAdapter { void unregisterAdapterStateCallbacks(in IUwbAdapterStateCallbacks callbacks); /** - * Returns true if ranging is supported, false otherwise - */ - boolean isRangingSupported(); - - /** - * Get the angle of arrival supported by this device - * - * @return the angle of arrival type supported - */ - AngleOfArrivalSupport getAngleOfArrivalSupport(); - - /** - * Generates a list of the supported 802.15.4z channels - * - * The list must be prioritized in the order of preferred channel usage. - * - * The list must only contain channels that are permitted to be used in the - * device's current location. - * - * @return an array of support channels on the device for the current location. - */ - int[] getSupportedChannels(); - - /** - * Generates a list of the supported 802.15.4z preamble codes - * - * The list must be prioritized in the order of preferred preamble usage. - * - * The list must only contain preambles that are permitted to be used in the - * device's current location. - * - * @return an array of supported preambles on the device for the current - * location. - */ - int[] getSupportedPreambleCodes(); - - /** * Get the accuracy of the ranging timestamps * * @return accuracy of the ranging timestamps in nanoseconds @@ -91,27 +53,6 @@ interface IUwbAdapter { long getTimestampResolutionNanos(); /** - * Get the supported number of simultaneous ranging sessions - * - * @return the supported number of simultaneous ranging sessions - */ - int getMaxSimultaneousSessions(); - - /** - * Get the maximum number of remote devices per session when local device is initiator - * - * @return the maximum number of remote devices supported in a single session - */ - int getMaxRemoteDevicesPerInitiatorSession(); - - /** - * Get the maximum number of remote devices per session when local device is responder - * - * @return the maximum number of remote devices supported in a single session - */ - int getMaxRemoteDevicesPerResponderSession(); - - /** * Provides the capabilities and features of the device * * @return specification specific capabilities and features of the device diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java index 2dc0ba0b9b80..63a6d058f358 100644 --- a/core/java/android/uwb/UwbManager.java +++ b/core/java/android/uwb/UwbManager.java @@ -32,10 +32,6 @@ import android.os.ServiceManager; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; import java.util.concurrent.Executor; /** @@ -195,133 +191,6 @@ public final class UwbManager { } /** - * Check if ranging is supported, regardless of ranging method - * - * @return true if ranging is supported - */ - @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) - public boolean isRangingSupported() { - try { - return mUwbAdapter.isRangingSupported(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * @hide - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(value = { - ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE, - ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D, - ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL, - ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL}) - public @interface AngleOfArrivalSupportType {} - - /** - * Indicate absence of support for angle of arrival measurement - */ - public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE = 1; - - /** - * Indicate support for planar angle of arrival measurement, due to antenna - * limitation. Typically requires at least two antennas. - */ - public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D = 2; - - /** - * Indicate support for three dimensional angle of arrival measurement. - * Typically requires at least three antennas. However, due to antenna - * arrangement, a platform may only support hemi-spherical azimuth angles - * ranging from -pi/2 to pi/2 - */ - public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL = 3; - - /** - * Indicate support for three dimensional angle of arrival measurement. - * Typically requires at least three antennas. This mode supports full - * azimuth angles ranging from -pi to pi. - */ - public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL = 4; - - /** - * Gets the {@link AngleOfArrivalSupportType} supported on this platform - * <p>Possible return values are - * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE}, - * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D}, - * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL}, - * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL}. - * - * @return angle of arrival type supported - */ - @AngleOfArrivalSupportType - @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) - public int getAngleOfArrivalSupport() { - try { - switch (mUwbAdapter.getAngleOfArrivalSupport()) { - case AngleOfArrivalSupport.TWO_DIMENSIONAL: - return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D; - - case AngleOfArrivalSupport.THREE_DIMENSIONAL_HEMISPHERICAL: - return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL; - - case AngleOfArrivalSupport.THREE_DIMENSIONAL_SPHERICAL: - return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL; - - case AngleOfArrivalSupport.NONE: - default: - return ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE; - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Get a {@link List} of supported channel numbers based on the device's current location - * <p>The returned values are ordered by the system's desired ordered of use, with the first - * entry being the most preferred. - * - * <p>Channel numbers are defined based on the IEEE 802.15.4z standard for UWB. - * - * @return {@link List} of supported channel numbers ordered by preference - */ - @NonNull - @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) - public List<Integer> getSupportedChannelNumbers() { - List<Integer> channels = new ArrayList<>(); - try { - for (int channel : mUwbAdapter.getSupportedChannels()) { - channels.add(channel); - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - return channels; - } - - /** - * Get a {@link List} of supported preamble code indices - * <p> Preamble code indices are defined based on the IEEE 802.15.4z standard for UWB. - * - * @return {@link List} of supported preamble code indices - */ - @NonNull - @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) - public Set<Integer> getSupportedPreambleCodeIndices() { - Set<Integer> preambles = new HashSet<>(); - try { - for (int preamble : mUwbAdapter.getSupportedPreambleCodes()) { - preambles.add(preamble); - } - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - return preambles; - } - - /** * Get the timestamp resolution for events in nanoseconds * <p>This value defines the maximum error of all timestamps for events reported to * {@link RangingSession.Callback}. @@ -339,50 +208,6 @@ public final class UwbManager { } /** - * Get the number of simultaneous sessions allowed in the system - * - * @return the maximum allowed number of simultaneously open {@link RangingSession} instances. - */ - @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) - public int getMaxSimultaneousSessions() { - try { - return mUwbAdapter.getMaxSimultaneousSessions(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Get the maximum number of remote devices in a {@link RangingSession} when the local device - * is the initiator. - * - * @return the maximum number of remote devices per {@link RangingSession} - */ - @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) - public int getMaxRemoteDevicesPerInitiatorSession() { - try { - return mUwbAdapter.getMaxRemoteDevicesPerInitiatorSession(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Get the maximum number of remote devices in a {@link RangingSession} when the local device - * is a responder. - * - * @return the maximum number of remote devices per {@link RangingSession} - */ - @RequiresPermission(Manifest.permission.UWB_PRIVILEGED) - public int getMaxRemoteDevicesPerResponderSession() { - try { - return mUwbAdapter.getMaxRemoteDevicesPerResponderSession(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** * Open a {@link RangingSession} with the given parameters * <p>The {@link RangingSession.Callback#onOpened(RangingSession)} function is called with a * {@link RangingSession} object used to control ranging when the session is successfully diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS index e66b17aa4426..c43c410ab995 100644 --- a/core/java/android/view/OWNERS +++ b/core/java/android/view/OWNERS @@ -77,3 +77,7 @@ per-file SyncRtSurfaceTransactionApplier.java = file:/services/core/java/com/and per-file ViewRootInsetsControllerHost.java = file:/services/core/java/com/android/server/wm/OWNERS per-file Window*.java = file:/services/core/java/com/android/server/wm/OWNERS per-file Window*.aidl = file:/services/core/java/com/android/server/wm/OWNERS + +# Scroll Capture +per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS +per-file *CaptureHelper*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 2d75b70333f2..c34b9f09ecaa 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -11879,16 +11879,17 @@ public class BatteryStatsImpl extends BatteryStats { final int numClusters = mPowerProfile.getNumCpuClusters(); mWakeLockAllocationsUs = null; final long startTimeMs = mClocks.uptimeMillis(); + final List<Integer> uidsToRemove = new ArrayList<>(); mCpuUidFreqTimeReader.readDelta((uid, cpuFreqTimeMs) -> { uid = mapUid(uid); if (Process.isIsolated(uid)) { - mCpuUidFreqTimeReader.removeUid(uid); + uidsToRemove.add(uid); Slog.d(TAG, "Got freq readings for an isolated uid with no mapping: " + uid); return; } if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) { Slog.d(TAG, "Got freq readings for an invalid user's uid " + uid); - mCpuUidFreqTimeReader.removeUid(uid); + uidsToRemove.add(uid); return; } final Uid u = getUidStatsLocked(uid); @@ -11947,6 +11948,9 @@ public class BatteryStatsImpl extends BatteryStats { } } }); + for (int uid : uidsToRemove) { + mCpuUidFreqTimeReader.removeUid(uid); + } final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs; if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) { @@ -11992,21 +11996,25 @@ public class BatteryStatsImpl extends BatteryStats { @VisibleForTesting public void readKernelUidCpuActiveTimesLocked(boolean onBattery) { final long startTimeMs = mClocks.uptimeMillis(); + final List<Integer> uidsToRemove = new ArrayList<>(); mCpuUidActiveTimeReader.readDelta((uid, cpuActiveTimesMs) -> { uid = mapUid(uid); if (Process.isIsolated(uid)) { - mCpuUidActiveTimeReader.removeUid(uid); + uidsToRemove.add(uid); Slog.w(TAG, "Got active times for an isolated uid with no mapping: " + uid); return; } if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) { Slog.w(TAG, "Got active times for an invalid user's uid " + uid); - mCpuUidActiveTimeReader.removeUid(uid); + uidsToRemove.add(uid); return; } final Uid u = getUidStatsLocked(uid); u.mCpuActiveTimeMs.addCountLocked(cpuActiveTimesMs, onBattery); }); + for (int uid : uidsToRemove) { + mCpuUidActiveTimeReader.removeUid(uid); + } final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs; if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) { @@ -12021,21 +12029,25 @@ public class BatteryStatsImpl extends BatteryStats { @VisibleForTesting public void readKernelUidCpuClusterTimesLocked(boolean onBattery) { final long startTimeMs = mClocks.uptimeMillis(); + final List<Integer> uidsToRemove = new ArrayList<>(); mCpuUidClusterTimeReader.readDelta((uid, cpuClusterTimesMs) -> { uid = mapUid(uid); if (Process.isIsolated(uid)) { - mCpuUidClusterTimeReader.removeUid(uid); + uidsToRemove.add(uid); Slog.w(TAG, "Got cluster times for an isolated uid with no mapping: " + uid); return; } if (!mUserInfoProvider.exists(UserHandle.getUserId(uid))) { Slog.w(TAG, "Got cluster times for an invalid user's uid " + uid); - mCpuUidClusterTimeReader.removeUid(uid); + uidsToRemove.add(uid); return; } final Uid u = getUidStatsLocked(uid); u.mCpuClusterTimesMs.addCountLocked(cpuClusterTimesMs, onBattery); }); + for (int uid : uidsToRemove) { + mCpuUidClusterTimeReader.removeUid(uid); + } final long elapsedTimeMs = mClocks.uptimeMillis() - startTimeMs; if (DEBUG_ENERGY_CPU || elapsedTimeMs >= 100) { diff --git a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java index f7fad2c5bbaa..2dd51b4459e7 100644 --- a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java +++ b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java @@ -143,6 +143,10 @@ public abstract class KernelCpuUidTimeReader<T> { */ public void removeUid(int uid) { mLastTimes.delete(uid); + + if (mBpfTimesAvailable) { + mBpfReader.removeUidsInRange(uid, uid); + } } /** diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 65beb9360241..d99f30567311 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -18,8 +18,8 @@ package com.android.internal.os; import static android.system.OsConstants.O_CLOEXEC; -import static com.android.internal.os.ZygoteConnectionConstants.MAX_ZYGOTE_ARGC; - +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.pm.ApplicationInfo; import android.net.Credentials; import android.net.LocalServerSocket; @@ -36,17 +36,16 @@ import android.util.Log; import com.android.internal.net.NetworkUtilsInternal; +import dalvik.annotation.optimization.CriticalNative; import dalvik.annotation.optimization.FastNative; import dalvik.system.ZygoteHooks; import libcore.io.IoUtils; -import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.FileDescriptor; import java.io.IOException; -import java.io.InputStreamReader; /** @hide */ public final class Zygote { @@ -103,7 +102,7 @@ public final class Zygote { */ public static final int PROFILE_FROM_SHELL = 1 << 15; - /** + /* * Enable using the ART app image startup cache */ public static final int USE_APP_IMAGE_STARTUP_CACHE = 1 << 16; @@ -116,7 +115,16 @@ public final class Zygote { */ public static final int DEBUG_IGNORE_APP_SIGNAL_HANDLER = 1 << 17; + /** + * Disable runtime access to {@link android.annotation.TestApi} annotated members. + * + * <p>This only takes effect if Hidden API access restrictions are enabled as well. + */ + public static final int DISABLE_TEST_API_ENFORCEMENT_POLICY = 1 << 18; + public static final int MEMORY_TAG_LEVEL_MASK = (1 << 19) | (1 << 20); + + public static final int MEMORY_TAG_LEVEL_NONE = 0; /** * Enable pointer tagging in this process. * Tags are checked during memory deallocation, but not on access. @@ -162,6 +170,11 @@ public final class Zygote { */ public static final int GWP_ASAN_LEVEL_ALWAYS = 2 << 21; + /** + * Enable automatic zero-initialization of native heap memory allocations. + */ + public static final int NATIVE_HEAP_ZERO_INIT = 1 << 23; + /** No external storage should be mounted. */ public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE; /** Default external storage should be mounted. */ @@ -236,6 +249,8 @@ public final class Zygote { */ public static final String CHILD_ZYGOTE_UID_RANGE_END = "--uid-range-end="; + private static final String TAG = "Zygote"; + /** Prefix prepended to socket names created by init */ private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_"; @@ -406,6 +421,10 @@ public final class Zygote { // Note that this event ends at the end of handleChildProc. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); + if (gids != null && gids.length > 0) { + NetworkUtilsInternal.setAllowNetworkingForProcess(containsInetGid(gids)); + } + // Set the Java Language thread priority to the default value for new apps. Thread.currentThread().setPriority(Thread.NORM_PRIORITY); @@ -578,114 +597,163 @@ public final class Zygote { private static native int nativeGetUsapPoolEventFD(); /** - * Fork a new unspecialized app process from the zygote + * Fork a new unspecialized app process from the zygote. Adds the Usap to the native + * Usap table. * * @param usapPoolSocket The server socket the USAP will call accept on - * @param sessionSocketRawFDs Anonymous session sockets that are currently open - * @param isPriorityFork Value controlling the process priority level until accept is called - * @return In the Zygote process this function will always return null; in unspecialized app - * processes this function will return a Runnable object representing the new - * application that is passed up from usapMain. + * @param sessionSocketRawFDs Anonymous session sockets that are currently open. + * These are closed in the child. + * @param isPriorityFork Raise the initial process priority level because this is on the + * critical path for application startup. + * @return In the child process, this returns a Runnable that waits for specialization + * info to start an app process. In the sygote/parent process this returns null. */ - static Runnable forkUsap(LocalServerSocket usapPoolSocket, - int[] sessionSocketRawFDs, - boolean isPriorityFork) { - FileDescriptor[] pipeFDs; + static @Nullable Runnable forkUsap(LocalServerSocket usapPoolSocket, + int[] sessionSocketRawFDs, + boolean isPriorityFork) { + FileDescriptor readFD; + FileDescriptor writeFD; try { - pipeFDs = Os.pipe2(O_CLOEXEC); + FileDescriptor[] pipeFDs = Os.pipe2(O_CLOEXEC); + readFD = pipeFDs[0]; + writeFD = pipeFDs[1]; } catch (ErrnoException errnoEx) { throw new IllegalStateException("Unable to create USAP pipe.", errnoEx); } - int pid = - nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(), - sessionSocketRawFDs, isPriorityFork); - + int pid = nativeForkApp(readFD.getInt$(), writeFD.getInt$(), + sessionSocketRawFDs, /*argsKnown=*/ false, isPriorityFork); if (pid == 0) { - IoUtils.closeQuietly(pipeFDs[0]); - return usapMain(usapPoolSocket, pipeFDs[1]); + IoUtils.closeQuietly(readFD); + return childMain(null, usapPoolSocket, writeFD); + } else if (pid == -1) { + // Fork failed. + return null; } else { - // The read-end of the pipe will be closed by the native code. - // See removeUsapTableEntry(); - IoUtils.closeQuietly(pipeFDs[1]); + // readFD will be closed by the native code. See removeUsapTableEntry(); + IoUtils.closeQuietly(writeFD); + nativeAddUsapTableEntry(pid, readFD.getInt$()); return null; } } - private static native int nativeForkUsap(int readPipeFD, - int writePipeFD, - int[] sessionSocketRawFDs, - boolean isPriorityFork); + private static native int nativeForkApp(int readPipeFD, + int writePipeFD, + int[] sessionSocketRawFDs, + boolean argsKnown, + boolean isPriorityFork); /** - * This function is used by unspecialized app processes to wait for specialization requests from - * the system server. + * Add an entry for a new Usap to the table maintained in native code. + */ + @CriticalNative + private static native void nativeAddUsapTableEntry(int pid, int readPipeFD); + + /** + * Fork a new app process from the zygote. argBuffer contains a fork command that + * request neither a child zygote, nor a wrapped process. Continue to accept connections + * on the specified socket, use those to refill argBuffer, and continue to process + * sufficiently simple fork requests. We presume that the only open file descriptors + * requiring special treatment are the session socket embedded in argBuffer, and + * zygoteSocket. + * @param argBuffer containing initial command and the connected socket from which to + * read more + * @param zygoteSocket socket from which to obtain new connections when current argBuffer + * one is disconnected + * @param expectedUId Uid of peer for initial requests. Subsequent requests from a different + * peer will cause us to return rather than perform the requested fork. + * @param minUid Minimum Uid enforced for all but first fork request. The caller checks + * the Uid policy for the initial request. + * @param firstNiceName name of first created process. Used for error reporting only. + * @return A Runnable in each child process, null in the parent. + * If this returns in then argBuffer still contains a command needing to be executed. + */ + static @Nullable Runnable forkSimpleApps(@NonNull ZygoteCommandBuffer argBuffer, + @NonNull FileDescriptor zygoteSocket, + int expectedUid, + int minUid, + @Nullable String firstNiceName) { + boolean in_child = + argBuffer.forkRepeatedly(zygoteSocket, expectedUid, minUid, firstNiceName); + if (in_child) { + return childMain(argBuffer, /*usapPoolSocket=*/null, /*writePipe=*/null); + } else { + return null; + } + } + + /** + * Specialize the current process into one described by argBuffer or the command read from + * usapPoolSocket. Exactly one of those must be null. If we are given an argBuffer, we close + * it. Used both for a specializing a USAP process, and for process creation without USAPs. + * In both cases, we specialize the process after first returning to Java code. * * @param writePipe The write end of the reporting pipe used to communicate with the poll loop * of the ZygoteServer. * @return A runnable oject representing the new application. */ - private static Runnable usapMain(LocalServerSocket usapPoolSocket, - FileDescriptor writePipe) { + private static Runnable childMain(@Nullable ZygoteCommandBuffer argBuffer, + @Nullable LocalServerSocket usapPoolSocket, + FileDescriptor writePipe) { final int pid = Process.myPid(); - Process.setArgV0(Process.is64Bit() ? "usap64" : "usap32"); - LocalSocket sessionSocket = null; DataOutputStream usapOutputStream = null; - Credentials peerCredentials = null; ZygoteArguments args = null; - // Change the priority to max before calling accept so we can respond to new specialization - // requests as quickly as possible. This will be reverted to the default priority in the - // native specialization code. - boostUsapPriority(); - - while (true) { - try { - sessionSocket = usapPoolSocket.accept(); + // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool. + blockSigTerm(); - // Block SIGTERM so we won't be killed if the Zygote flushes the USAP pool. - blockSigTerm(); - - BufferedReader usapReader = - new BufferedReader(new InputStreamReader(sessionSocket.getInputStream())); - usapOutputStream = - new DataOutputStream(sessionSocket.getOutputStream()); - - peerCredentials = sessionSocket.getPeerCredentials(); + LocalSocket sessionSocket = null; + if (argBuffer == null) { + // Read arguments from usapPoolSocket instead. - String[] argStrings = readArgumentList(usapReader); + Process.setArgV0(Process.is64Bit() ? "usap64" : "usap32"); - if (argStrings != null) { - args = new ZygoteArguments(argStrings); + // Change the priority to max before calling accept so we can respond to new + // specialization requests as quickly as possible. This will be reverted to the + // default priority in the native specialization code. + boostUsapPriority(); + while (true) { + ZygoteCommandBuffer tmpArgBuffer = null; + try { + sessionSocket = usapPoolSocket.accept(); + + usapOutputStream = + new DataOutputStream(sessionSocket.getOutputStream()); + Credentials peerCredentials = sessionSocket.getPeerCredentials(); + tmpArgBuffer = new ZygoteCommandBuffer(sessionSocket); + args = ZygoteArguments.getInstance(argBuffer); + applyUidSecurityPolicy(args, peerCredentials); // TODO (chriswailes): Should this only be run for debug builds? validateUsapCommand(args); break; - } else { - Log.e("USAP", "Truncated command received."); - IoUtils.closeQuietly(sessionSocket); - - // Re-enable SIGTERM so the USAP can be flushed from the pool if necessary. - unblockSigTerm(); + } catch (Exception ex) { + Log.e("USAP", ex.getMessage()); } - } catch (Exception ex) { - Log.e("USAP", ex.getMessage()); - IoUtils.closeQuietly(sessionSocket); - // Re-enable SIGTERM so the USAP can be flushed from the pool if necessary. unblockSigTerm(); + IoUtils.closeQuietly(sessionSocket); + IoUtils.closeQuietly(tmpArgBuffer); + blockSigTerm(); } + } else { + try { + args = ZygoteArguments.getInstance(argBuffer); + } catch (Exception ex) { + Log.e("AppStartup", ex.getMessage()); + throw new AssertionError("Failed to parse application start command", ex); + } + // peerCredentials were checked in parent. + } + if (args == null) { + throw new AssertionError("Empty command line"); } - try { - // SIGTERM is blocked on loop exit. This prevents a USAP that is specializing from - // being killed during a pool flush. - - setAppProcessName(args, "USAP"); + // SIGTERM is blocked here. This prevents a USAP that is specializing from being + // killed during a pool flush. - applyUidSecurityPolicy(args, peerCredentials); applyDebuggerSystemProperty(args); int[][] rlimits = null; @@ -694,53 +762,57 @@ public final class Zygote { rlimits = args.mRLimits.toArray(INT_ARRAY_2D); } - // This must happen before the SELinux policy for this process is - // changed when specializing. - try { - // Used by ZygoteProcess.zygoteSendArgsAndGetResult to fill in a - // Process.ProcessStartResult object. - usapOutputStream.writeInt(pid); - } catch (IOException ioEx) { - Log.e("USAP", "Failed to write response to session socket: " - + ioEx.getMessage()); - throw new RuntimeException(ioEx); - } finally { - IoUtils.closeQuietly(sessionSocket); - + if (argBuffer == null) { + // This must happen before the SELinux policy for this process is + // changed when specializing. try { - // This socket is closed using Os.close due to an issue with the implementation - // of LocalSocketImp.close(). Because the raw FD is created by init and then - // loaded from an environment variable (as opposed to being created by the - // LocalSocketImpl itself) the current implementation will not actually close - // the underlying FD. - // - // See b/130309968 for discussion of this issue. - Os.close(usapPoolSocket.getFileDescriptor()); - } catch (ErrnoException ex) { - Log.e("USAP", "Failed to close USAP pool socket"); - throw new RuntimeException(ex); + // Used by ZygoteProcess.zygoteSendArgsAndGetResult to fill in a + // Process.ProcessStartResult object. + usapOutputStream.writeInt(pid); + } catch (IOException ioEx) { + Log.e("USAP", "Failed to write response to session socket: " + + ioEx.getMessage()); + throw new RuntimeException(ioEx); + } finally { + try { + // Since the raw FD is created by init and then loaded from an environment + // variable (as opposed to being created by the LocalSocketImpl itself), + // the LocalSocket/LocalSocketImpl does not own the Os-level socket. See + // the spec for LocalSocket.createConnectedLocalSocket(FileDescriptor fd). + // Thus closing the LocalSocket does not suffice. See b/130309968 for more + // discussion. + FileDescriptor fd = usapPoolSocket.getFileDescriptor(); + usapPoolSocket.close(); + Os.close(fd); + } catch (ErrnoException | IOException ex) { + Log.e("USAP", "Failed to close USAP pool socket"); + throw new RuntimeException(ex); + } } } - try { - ByteArrayOutputStream buffer = - new ByteArrayOutputStream(Zygote.USAP_MANAGEMENT_MESSAGE_BYTES); - DataOutputStream outputStream = new DataOutputStream(buffer); - - // This is written as a long so that the USAP reporting pipe and USAP pool event FD - // handlers in ZygoteServer.runSelectLoop can be unified. These two cases should - // both send/receive 8 bytes. - outputStream.writeLong(pid); - outputStream.flush(); - - Os.write(writePipe, buffer.toByteArray(), 0, buffer.size()); - } catch (Exception ex) { - Log.e("USAP", - String.format("Failed to write PID (%d) to pipe (%d): %s", - pid, writePipe.getInt$(), ex.getMessage())); - throw new RuntimeException(ex); - } finally { - IoUtils.closeQuietly(writePipe); + if (writePipe != null) { + try { + ByteArrayOutputStream buffer = + new ByteArrayOutputStream(Zygote.USAP_MANAGEMENT_MESSAGE_BYTES); + DataOutputStream outputStream = new DataOutputStream(buffer); + + // This is written as a long so that the USAP reporting pipe and USAP pool + // event FD handlers in ZygoteServer.runSelectLoop can be unified. These two + // cases should both send/receive 8 bytes. + // TODO: Needs tweaking to handle the non-Usap invoke-with case, which expects + // a different format. + outputStream.writeLong(pid); + outputStream.flush(); + Os.write(writePipe, buffer.toByteArray(), 0, buffer.size()); + } catch (Exception ex) { + Log.e("USAP", + String.format("Failed to write PID (%d) to pipe (%d): %s", + pid, writePipe.getInt$(), ex.getMessage())); + throw new RuntimeException(ex); + } finally { + IoUtils.closeQuietly(writePipe); + } } specializeAppProcess(args.mUid, args.mGid, args.mGids, @@ -847,13 +919,29 @@ public final class Zygote { return nativeRemoveUsapTableEntry(usapPID); } + @CriticalNative private static native boolean nativeRemoveUsapTableEntry(int usapPID); /** - * uid 1000 (Process.SYSTEM_UID) may specify any uid > 1000 in normal + * Return the minimum child uid that the given peer is allowed to create. + * uid 1000 (Process.SYSTEM_UID) may specify any uid ≥ 1000 in normal * operation. It may also specify any gid and setgroups() list it chooses. * In factory test mode, it may specify any UID. - * + */ + static int minChildUid(Credentials peer) { + if (peer.getUid() == Process.SYSTEM_UID + && FactoryTest.getMode() == FactoryTest.FACTORY_TEST_OFF) { + /* In normal operation, SYSTEM_UID can only specify a restricted + * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid. + */ + return Process.SYSTEM_UID; + } else { + return 0; + } + } + + /* + * Adjust uid and gid arguments, ensuring that the security policy is satisfied. * @param args non-null; zygote spawner arguments * @param peer non-null; peer credentials * @throws ZygoteSecurityException Indicates a security issue when applying the UID based @@ -862,17 +950,10 @@ public final class Zygote { static void applyUidSecurityPolicy(ZygoteArguments args, Credentials peer) throws ZygoteSecurityException { - if (peer.getUid() == Process.SYSTEM_UID) { - /* In normal operation, SYSTEM_UID can only specify a restricted - * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid. - */ - boolean uidRestricted = FactoryTest.getMode() == FactoryTest.FACTORY_TEST_OFF; - - if (uidRestricted && args.mUidSpecified && (args.mUid < Process.SYSTEM_UID)) { - throw new ZygoteSecurityException( - "System UID may not launch process with UID < " - + Process.SYSTEM_UID); - } + if (args.mUidSpecified && (args.mUid < minChildUid(peer))) { + throw new ZygoteSecurityException( + "System UID may not launch process with UID < " + + Process.SYSTEM_UID); } // If not otherwise specified, uid and gid are inherited from peer @@ -958,45 +1039,6 @@ public final class Zygote { } /** - * Reads an argument list from the provided socket - * @return Argument list or null if EOF is reached - * @throws IOException passed straight through - */ - static String[] readArgumentList(BufferedReader socketReader) throws IOException { - int argc; - - try { - String argc_string = socketReader.readLine(); - - if (argc_string == null) { - // EOF reached. - return null; - } - argc = Integer.parseInt(argc_string); - - } catch (NumberFormatException ex) { - Log.e("Zygote", "Invalid Zygote wire format: non-int at argc"); - throw new IOException("Invalid wire format"); - } - - // See bug 1092107: large argc can be used for a DOS attack - if (argc > MAX_ZYGOTE_ARGC) { - throw new IOException("Max arg count exceeded"); - } - - String[] args = new String[argc]; - for (int arg_index = 0; arg_index < argc; arg_index++) { - args[arg_index] = socketReader.readLine(); - if (args[arg_index] == null) { - // We got an unexpected EOF. - throw new IOException("Truncated request"); - } - } - - return args; - } - - /** * Creates a managed LocalServerSocket object using a file descriptor * created by an init.rc script. The init scripts that specify the * sockets name can be found in system/core/rootdir. The socket is bound diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java index ed074327c3c5..5a1c1710d32b 100644 --- a/core/java/com/android/internal/os/ZygoteArguments.java +++ b/core/java/com/android/internal/os/ZygoteArguments.java @@ -16,8 +16,8 @@ package com.android.internal.os; +import java.io.EOFException; import java.util.ArrayList; -import java.util.Arrays; /** * Handles argument parsing for args related to the zygote spawner. @@ -245,20 +245,34 @@ class ZygoteArguments { /** * Constructs instance and parses args * - * @param args zygote command-line args + * @param args zygote command-line args as ZygoteCommandBuffer, positioned after argument count. */ - ZygoteArguments(String[] args) throws IllegalArgumentException { - parseArgs(args); + private ZygoteArguments(ZygoteCommandBuffer args, int argCount) + throws IllegalArgumentException, EOFException { + parseArgs(args, argCount); + } + + /** + * Return a new ZygoteArguments reflecting the contents of the given ZygoteCommandBuffer. Return + * null if the ZygoteCommandBuffer was positioned at EOF. Assumes the buffer is initially + * positioned at the beginning of the command. + */ + public static ZygoteArguments getInstance(ZygoteCommandBuffer args) + throws IllegalArgumentException, EOFException { + int argCount = args.getCount(); + return argCount == 0 ? null : new ZygoteArguments(args, argCount); } /** * Parses the commandline arguments intended for the Zygote spawner (such as "--setuid=" and - * "--setgid=") and creates an array containing the remaining args. + * "--setgid=") and creates an array containing the remaining args. Return false if we were + * at EOF. * * Per security review bug #1112214, duplicate args are disallowed in critical cases to make * injection harder. */ - private void parseArgs(String[] args) throws IllegalArgumentException { + private void parseArgs(ZygoteCommandBuffer args, int argCount) + throws IllegalArgumentException, EOFException { /* * See android.os.ZygoteProcess.zygoteSendArgsAndGetResult() * Presently the wire format to the zygote process is: @@ -269,13 +283,13 @@ class ZygoteArguments { * the child or -1 on failure. */ - int curArg = 0; - + String unprocessedArg = null; + int curArg = 0; // Index of arg boolean seenRuntimeArgs = false; - boolean expectRuntimeArgs = true; - for ( /* curArg */ ; curArg < args.length; curArg++) { - String arg = args[curArg]; + + for ( /* curArg */ ; curArg < argCount; ++curArg) { + String arg = args.nextArg(); if (arg.equals("--")) { curArg++; @@ -367,7 +381,8 @@ class ZygoteArguments { "Duplicate arg specified"); } try { - mInvokeWith = args[++curArg]; + ++curArg; + mInvokeWith = args.nextArg(); } catch (IndexOutOfBoundsException ex) { throw new IllegalArgumentException( "--invoke-with requires argument"); @@ -405,12 +420,14 @@ class ZygoteArguments { } else if (arg.startsWith("--app-data-dir=")) { mAppDataDir = getAssignmentValue(arg); } else if (arg.equals("--preload-app")) { - mPreloadApp = args[++curArg]; + ++curArg; + mPreloadApp = args.nextArg(); } else if (arg.equals("--preload-package")) { - mPreloadPackage = args[++curArg]; - mPreloadPackageLibs = args[++curArg]; - mPreloadPackageLibFileName = args[++curArg]; - mPreloadPackageCacheKey = args[++curArg]; + curArg += 4; + mPreloadPackage = args.nextArg(); + mPreloadPackageLibs = args.nextArg(); + mPreloadPackageLibFileName = args.nextArg(); + mPreloadPackageCacheKey = args.nextArg(); } else if (arg.equals("--preload-default")) { mPreloadDefault = true; expectRuntimeArgs = false; @@ -419,8 +436,11 @@ class ZygoteArguments { } else if (arg.equals("--set-api-denylist-exemptions")) { // consume all remaining args; this is a stand-alone command, never included // with the regular fork command. - mApiDenylistExemptions = Arrays.copyOfRange(args, curArg + 1, args.length); - curArg = args.length; + mApiDenylistExemptions = new String[argCount - curArg - 1]; + ++curArg; + for (int i = 0; curArg < argCount; ++curArg, ++i) { + mApiDenylistExemptions[i] = args.nextArg(); + } expectRuntimeArgs = false; } else if (arg.startsWith("--hidden-api-log-sampling-rate=")) { String rateStr = getAssignmentValue(arg); @@ -470,35 +490,46 @@ class ZygoteArguments { } else if (arg.equals(Zygote.BIND_MOUNT_APP_DATA_DIRS)) { mBindMountAppDataDirs = true; } else { + unprocessedArg = arg; break; } } + // curArg is the index of the first unprocessed argument. That argument is either referenced + // by unprocessedArg or not read yet. if (mBootCompleted) { - if (args.length - curArg > 0) { + if (argCount > curArg) { throw new IllegalArgumentException("Unexpected arguments after --boot-completed"); } } else if (mAbiListQuery || mPidQuery) { - if (args.length - curArg > 0) { + if (argCount > curArg) { throw new IllegalArgumentException("Unexpected arguments after --query-abi-list."); } } else if (mPreloadPackage != null) { - if (args.length - curArg > 0) { + if (argCount > curArg) { throw new IllegalArgumentException( "Unexpected arguments after --preload-package."); } } else if (mPreloadApp != null) { - if (args.length - curArg > 0) { + if (argCount > curArg) { throw new IllegalArgumentException( "Unexpected arguments after --preload-app."); } } else if (expectRuntimeArgs) { if (!seenRuntimeArgs) { - throw new IllegalArgumentException("Unexpected argument : " + args[curArg]); + throw new IllegalArgumentException("Unexpected argument : " + + (unprocessedArg == null ? args.nextArg() : unprocessedArg)); } - mRemainingArgs = new String[args.length - curArg]; - System.arraycopy(args, curArg, mRemainingArgs, 0, mRemainingArgs.length); + mRemainingArgs = new String[argCount - curArg]; + int i = 0; + if (unprocessedArg != null) { + mRemainingArgs[0] = unprocessedArg; + ++i; + } + for (; i < argCount - curArg; ++i) { + mRemainingArgs[i] = args.nextArg(); + } } if (mStartChildZygote) { diff --git a/core/java/com/android/internal/os/ZygoteCommandBuffer.java b/core/java/com/android/internal/os/ZygoteCommandBuffer.java new file mode 100644 index 000000000000..b61ae7acfacd --- /dev/null +++ b/core/java/com/android/internal/os/ZygoteCommandBuffer.java @@ -0,0 +1,187 @@ +/* + * 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.internal.os; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.LocalSocket; + +import java.io.FileDescriptor; +import java.lang.ref.Reference; // For reachabilityFence. + +/** + * A native-accessible buffer for Zygote commands. Designed to support repeated forking + * of applications without intervening memory allocation, thus keeping zygote memory + * as stable as possible. + * A ZygoteCommandBuffer may have an associated socket from which it can be refilled. + * Otherwise the contents are explicitly set by getInstance(). + * + * NOT THREAD-SAFE. No methods may be called concurrently from multiple threads. + * + * Only one ZygoteCommandBuffer can exist at a time. + * Must be explicitly closed before being dropped. + * @hide + */ +class ZygoteCommandBuffer implements AutoCloseable { + private long mNativeBuffer; // Not final so that we can clear it in close(). + + /** + * The command socket. + * + * mSocket is retained in the child process in "peer wait" mode, so + * that it closes when the child process terminates. In other cases, + * it is closed in the peer. + */ + private final LocalSocket mSocket; + private final int mNativeSocket; + + /** + * Constructs instance from file descriptor from which the command will be read. + * Only a single instance may be live in a given process. The native code checks. + * + * @param fd file descriptor to read from. The setCommand() method may be used if and only if + * fd is null. + */ + ZygoteCommandBuffer(@Nullable LocalSocket socket) { + mSocket = socket; + if (socket == null) { + mNativeSocket = -1; + } else { + mNativeSocket = mSocket.getFileDescriptor().getInt$(); + } + mNativeBuffer = getNativeBuffer(mNativeSocket); + } + + /** + * Constructs an instance with explicitly supplied arguments and an invalid + * file descriptor. Can only be used for a single command. + */ + ZygoteCommandBuffer(@NonNull String[] args) { + this((LocalSocket) null); + setCommand(args); + } + + + private static native long getNativeBuffer(int fd); + + /** + * Deallocate native resources associated with the one and only command buffer, and prevent + * reuse. Subsequent calls to getInstance() will yield a new buffer. + * We do not close the associated socket, if any. + */ + @Override + public void close() { + freeNativeBuffer(mNativeBuffer); + mNativeBuffer = 0; + } + + private static native void freeNativeBuffer(long /* NativeCommandBuffer* */ nbuffer); + + /** + * Read at least the first line of the next command into the buffer, return the argument count + * from that line. Assumes we are initially positioned at the beginning of the first line of + * the command. Leave the buffer positioned at the beginning of the second command line, i.e. + * the first argument. If the buffer has no associated file descriptor, we just reposition to + * the beginning of the buffer, and reread existing contents. Returns zero if we started out + * at EOF. + */ + int getCount() { + try { + return nativeGetCount(mNativeBuffer); + } finally { + // Make sure the mNativeSocket doesn't get closed due to early finalization. + Reference.reachabilityFence(mSocket); + } + } + + private static native int nativeGetCount(long /* NativeCommandBuffer* */ nbuffer); + + + /* + * Set the buffer to contain the supplied sequence of arguments. + */ + private void setCommand(String[] command) { + int nArgs = command.length; + insert(mNativeBuffer, Integer.toString(nArgs)); + for (String s: command) { + insert(mNativeBuffer, s); + } + // Native code checks there is no socket; hence no reachabilityFence. + } + + private static native void insert(long /* NativeCommandBuffer* */ nbuffer, String s); + + /** + * Retrieve the next argument/line from the buffer, filling the buffer as necessary. + */ + String nextArg() { + try { + return nativeNextArg(mNativeBuffer); + } finally { + Reference.reachabilityFence(mSocket); + } + } + + private static native String nativeNextArg(long /* NativeCommandBuffer* */ nbuffer); + + void readFullyAndReset() { + try { + nativeReadFullyAndReset(mNativeBuffer); + } finally { + Reference.reachabilityFence(mSocket); + } + } + + private static native void nativeReadFullyAndReset(long /* NativeCommandBuffer* */ nbuffer); + + /** + * Fork a child as specified by the current command in the buffer, and repeat this process + * after refilling the buffer, so long as the buffer clearly contains another fork command. + * + * @param zygoteSocket socket from which to obtain new connections when current one is + * disconnected + * @param expectedUid Peer UID for current connection. We refuse to deal with requests from + * a different UID. + * @param minUid the smallest uid that may be request for the child process. + * @param firstNiceName The name for the initial process to be forked. Used only for error + * reporting. + * + * @return true in the child, false in the parent. In the parent case, the buffer is positioned + * at the beginning of a command that still needs to be processed. + */ + boolean forkRepeatedly(FileDescriptor zygoteSocket, int expectedUid, int minUid, + String firstNiceName) { + try { + return nativeForkRepeatedly(mNativeBuffer, zygoteSocket.getInt$(), + expectedUid, minUid, firstNiceName); + } finally { + Reference.reachabilityFence(mSocket); + Reference.reachabilityFence(zygoteSocket); + } + } + + /* + * Repeatedly fork children as above. It commonly does not return in the parent, but it may. + * @return true in the chaild, false in the parent if we encounter a command we couldn't handle. + */ + private static native boolean nativeForkRepeatedly(long /* NativeCommandBuffer* */ nbuffer, + int zygoteSocketRawFd, + int expectedUid, + int minUid, + String firstNiceName); + +} diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 5a576ebbc442..37c75907061c 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -36,16 +36,15 @@ import android.system.StructPollfd; import android.util.Log; import dalvik.system.VMRuntime; +import dalvik.system.ZygoteHooks; import libcore.io.IoUtils; -import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileDescriptor; import java.io.IOException; -import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.concurrent.TimeUnit; @@ -67,7 +66,6 @@ class ZygoteConnection { private final LocalSocket mSocket; @UnsupportedAppUsage private final DataOutputStream mSocketOutStream; - private final BufferedReader mSocketReader; @UnsupportedAppUsage private final Credentials peer; private final String abiList; @@ -85,9 +83,6 @@ class ZygoteConnection { this.abiList = abiList; mSocketOutStream = new DataOutputStream(socket.getOutputStream()); - mSocketReader = - new BufferedReader( - new InputStreamReader(socket.getInputStream()), Zygote.SOCKET_BUFFER_SIZE); mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS); @@ -111,178 +106,216 @@ class ZygoteConnection { } /** - * Reads one start command from the command socket. If successful, a child is forked and a + * Reads a command from the command socket. If a child is successfully forked, a * {@code Runnable} that calls the childs main method (or equivalent) is returned in the child * process. {@code null} is always returned in the parent process (the zygote). + * If multipleOK is set, we may keep processing additional fork commands before returning. * * If the client closes the socket, an {@code EOF} condition is set, which callers can test * for by calling {@code ZygoteConnection.isClosedByPeer}. */ - Runnable processOneCommand(ZygoteServer zygoteServer) { - String[] args; - - try { - args = Zygote.readArgumentList(mSocketReader); - } catch (IOException ex) { - throw new IllegalStateException("IOException on command socket", ex); - } - - // readArgumentList returns null only when it has reached EOF with no available - // data to read. This will only happen when the remote socket has disconnected. - if (args == null) { - isEof = true; - return null; - } - - int pid; - FileDescriptor childPipeFd = null; - FileDescriptor serverPipeFd = null; - - ZygoteArguments parsedArgs = new ZygoteArguments(args); - - if (parsedArgs.mBootCompleted) { - handleBootCompleted(); - return null; - } - - if (parsedArgs.mAbiListQuery) { - handleAbiListQuery(); - return null; - } - - if (parsedArgs.mPidQuery) { - handlePidQuery(); - return null; - } + Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) { + ZygoteArguments parsedArgs; + + try (ZygoteCommandBuffer argBuffer = new ZygoteCommandBuffer(mSocket)) { + while (true) { + try { + parsedArgs = ZygoteArguments.getInstance(argBuffer); + // Keep argBuffer around, since we need it to fork. + } catch (IOException ex) { + throw new IllegalStateException("IOException on command socket", ex); + } + if (parsedArgs == null) { + isEof = true; + return null; + } - if (parsedArgs.mUsapPoolStatusSpecified) { - return handleUsapPoolStatusChange(zygoteServer, parsedArgs.mUsapPoolEnabled); - } + int pid; + FileDescriptor childPipeFd = null; + FileDescriptor serverPipeFd = null; - if (parsedArgs.mPreloadDefault) { - handlePreload(); - return null; - } + if (parsedArgs.mBootCompleted) { + handleBootCompleted(); + return null; + } - if (parsedArgs.mPreloadPackage != null) { - handlePreloadPackage(parsedArgs.mPreloadPackage, parsedArgs.mPreloadPackageLibs, - parsedArgs.mPreloadPackageLibFileName, parsedArgs.mPreloadPackageCacheKey); - return null; - } + if (parsedArgs.mAbiListQuery) { + handleAbiListQuery(); + return null; + } - if (canPreloadApp() && parsedArgs.mPreloadApp != null) { - byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp); - Parcel appInfoParcel = Parcel.obtain(); - appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length); - appInfoParcel.setDataPosition(0); - ApplicationInfo appInfo = ApplicationInfo.CREATOR.createFromParcel(appInfoParcel); - appInfoParcel.recycle(); - if (appInfo != null) { - handlePreloadApp(appInfo); - } else { - throw new IllegalArgumentException("Failed to deserialize --preload-app"); - } - return null; - } + if (parsedArgs.mPidQuery) { + handlePidQuery(); + return null; + } - if (parsedArgs.mApiDenylistExemptions != null) { - return handleApiDenylistExemptions(zygoteServer, parsedArgs.mApiDenylistExemptions); - } + if (parsedArgs.mUsapPoolStatusSpecified) { + // Handle this once we've released the argBuffer, to avoid opening a second one. + break; + } - if (parsedArgs.mHiddenApiAccessLogSampleRate != -1 - || parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) { - return handleHiddenApiAccessLogSampleRate(zygoteServer, - parsedArgs.mHiddenApiAccessLogSampleRate, - parsedArgs.mHiddenApiAccessStatslogSampleRate); - } + if (parsedArgs.mPreloadDefault) { + handlePreload(); + return null; + } - if (parsedArgs.mPermittedCapabilities != 0 || parsedArgs.mEffectiveCapabilities != 0) { - throw new ZygoteSecurityException("Client may not specify capabilities: " - + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities) - + ", effective=0x" + Long.toHexString(parsedArgs.mEffectiveCapabilities)); - } + if (parsedArgs.mPreloadPackage != null) { + handlePreloadPackage(parsedArgs.mPreloadPackage, + parsedArgs.mPreloadPackageLibs, + parsedArgs.mPreloadPackageLibFileName, + parsedArgs.mPreloadPackageCacheKey); + return null; + } - Zygote.applyUidSecurityPolicy(parsedArgs, peer); - Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer); + if (canPreloadApp() && parsedArgs.mPreloadApp != null) { + byte[] rawParcelData = Base64.getDecoder().decode(parsedArgs.mPreloadApp); + Parcel appInfoParcel = Parcel.obtain(); + appInfoParcel.unmarshall(rawParcelData, 0, rawParcelData.length); + appInfoParcel.setDataPosition(0); + ApplicationInfo appInfo = + ApplicationInfo.CREATOR.createFromParcel(appInfoParcel); + appInfoParcel.recycle(); + if (appInfo != null) { + handlePreloadApp(appInfo); + } else { + throw new IllegalArgumentException("Failed to deserialize --preload-app"); + } + return null; + } - Zygote.applyDebuggerSystemProperty(parsedArgs); - Zygote.applyInvokeWithSystemProperty(parsedArgs); + if (parsedArgs.mApiDenylistExemptions != null) { + return handleApiDenylistExemptions(zygoteServer, + parsedArgs.mApiDenylistExemptions); + } - int[][] rlimits = null; + if (parsedArgs.mHiddenApiAccessLogSampleRate != -1 + || parsedArgs.mHiddenApiAccessStatslogSampleRate != -1) { + return handleHiddenApiAccessLogSampleRate(zygoteServer, + parsedArgs.mHiddenApiAccessLogSampleRate, + parsedArgs.mHiddenApiAccessStatslogSampleRate); + } - if (parsedArgs.mRLimits != null) { - rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D); - } + if (parsedArgs.mPermittedCapabilities != 0 + || parsedArgs.mEffectiveCapabilities != 0) { + throw new ZygoteSecurityException("Client may not specify capabilities: " + + "permitted=0x" + Long.toHexString(parsedArgs.mPermittedCapabilities) + + ", effective=0x" + + Long.toHexString(parsedArgs.mEffectiveCapabilities)); + } - int[] fdsToIgnore = null; + Zygote.applyUidSecurityPolicy(parsedArgs, peer); + Zygote.applyInvokeWithSecurityPolicy(parsedArgs, peer); - if (parsedArgs.mInvokeWith != null) { - try { - FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC); - childPipeFd = pipeFds[1]; - serverPipeFd = pipeFds[0]; - Os.fcntlInt(childPipeFd, F_SETFD, 0); - fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()}; - } catch (ErrnoException errnoEx) { - throw new IllegalStateException("Unable to set up pipe for invoke-with", errnoEx); - } - } + Zygote.applyDebuggerSystemProperty(parsedArgs); + Zygote.applyInvokeWithSystemProperty(parsedArgs); - /* - * In order to avoid leaking descriptors to the Zygote child, - * the native code must close the two Zygote socket descriptors - * in the child process before it switches from Zygote-root to - * the UID and privileges of the application being launched. - * - * In order to avoid "bad file descriptor" errors when the - * two LocalSocket objects are closed, the Posix file - * descriptors are released via a dup2() call which closes - * the socket and substitutes an open descriptor to /dev/null. - */ + int[][] rlimits = null; - int [] fdsToClose = { -1, -1 }; + if (parsedArgs.mRLimits != null) { + rlimits = parsedArgs.mRLimits.toArray(Zygote.INT_ARRAY_2D); + } - FileDescriptor fd = mSocket.getFileDescriptor(); + int[] fdsToIgnore = null; + + if (parsedArgs.mInvokeWith != null) { + try { + FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC); + childPipeFd = pipeFds[1]; + serverPipeFd = pipeFds[0]; + Os.fcntlInt(childPipeFd, F_SETFD, 0); + fdsToIgnore = new int[]{childPipeFd.getInt$(), serverPipeFd.getInt$()}; + } catch (ErrnoException errnoEx) { + throw new IllegalStateException("Unable to set up pipe for invoke-with", + errnoEx); + } + } - if (fd != null) { - fdsToClose[0] = fd.getInt$(); - } + /* + * In order to avoid leaking descriptors to the Zygote child, + * the native code must close the two Zygote socket descriptors + * in the child process before it switches from Zygote-root to + * the UID and privileges of the application being launched. + * + * In order to avoid "bad file descriptor" errors when the + * two LocalSocket objects are closed, the Posix file + * descriptors are released via a dup2() call which closes + * the socket and substitutes an open descriptor to /dev/null. + */ - fd = zygoteServer.getZygoteSocketFileDescriptor(); + int [] fdsToClose = { -1, -1 }; - if (fd != null) { - fdsToClose[1] = fd.getInt$(); - } + FileDescriptor fd = mSocket.getFileDescriptor(); - pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids, - parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo, - parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote, - parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp, - parsedArgs.mPkgDataInfoList, parsedArgs.mWhitelistedDataInfoList, - parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs); + if (fd != null) { + fdsToClose[0] = fd.getInt$(); + } - try { - if (pid == 0) { - // in child - zygoteServer.setForkChild(); + FileDescriptor zygoteFd = zygoteServer.getZygoteSocketFileDescriptor(); - zygoteServer.closeServerSocket(); - IoUtils.closeQuietly(serverPipeFd); - serverPipeFd = null; + if (zygoteFd != null) { + fdsToClose[1] = zygoteFd.getInt$(); + } - return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote); - } else { - // In the parent. A pid < 0 indicates a failure and will be handled in - // handleParentProc. - IoUtils.closeQuietly(childPipeFd); - childPipeFd = null; - handleParentProc(pid, serverPipeFd); - return null; + if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote + || !multipleOK || peer.getUid() != Process.SYSTEM_UID) { + // Continue using old code for now. TODO: Handle these cases in the other path. + pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, + parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits, + parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName, + fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote, + parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, + parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList, + parsedArgs.mWhitelistedDataInfoList, parsedArgs.mBindMountAppDataDirs, + parsedArgs.mBindMountAppStorageDirs); + + try { + if (pid == 0) { + // in child + zygoteServer.setForkChild(); + + zygoteServer.closeServerSocket(); + IoUtils.closeQuietly(serverPipeFd); + serverPipeFd = null; + + return handleChildProc(parsedArgs, childPipeFd, + parsedArgs.mStartChildZygote); + } else { + // In the parent. A pid < 0 indicates a failure and will be handled in + // handleParentProc. + IoUtils.closeQuietly(childPipeFd); + childPipeFd = null; + handleParentProc(pid, serverPipeFd); + return null; + } + } finally { + IoUtils.closeQuietly(childPipeFd); + IoUtils.closeQuietly(serverPipeFd); + } + } else { + ZygoteHooks.preFork(); + Runnable result = Zygote.forkSimpleApps(argBuffer, + zygoteServer.getZygoteSocketFileDescriptor(), + peer.getUid(), Zygote.minChildUid(peer), parsedArgs.mNiceName); + if (result == null) { + // parent; we finished some number of forks. Result is Boolean. + // We already did the equivalent of handleParentProc(). + ZygoteHooks.postForkCommon(); + // argBuffer contains a command not understood by forksimpleApps. + continue; + } else { + // child; result is a Runnable. + zygoteServer.setForkChild(); + Zygote.setAppProcessName(parsedArgs, TAG); // ??? Necessary? + return result; + } + } } - } finally { - IoUtils.closeQuietly(childPipeFd); - IoUtils.closeQuietly(serverPipeFd); } + if (parsedArgs.mUsapPoolStatusSpecified) { + // Now that we've released argBuffer: + return handleUsapPoolStatusChange(zygoteServer, parsedArgs.mUsapPoolEnabled); + } + throw new AssertionError("Shouldn't get here"); } private void handleAbiListQuery() { @@ -557,7 +590,7 @@ class ZygoteConnection { if (res > 0) { if ((fds[0].revents & POLLIN) != 0) { - // Only read one byte, so as not to block. + // Only read one byte, so as not to block. Really needed? int readBytes = android.system.Os.read(pipeFd, data, dataIndex, 1); if (readBytes < 0) { throw new RuntimeException("Some error"); diff --git a/core/java/com/android/internal/os/ZygoteConnectionConstants.java b/core/java/com/android/internal/os/ZygoteConnectionConstants.java index 506e39f30617..0c1cd6de1bb4 100644 --- a/core/java/com/android/internal/os/ZygoteConnectionConstants.java +++ b/core/java/com/android/internal/os/ZygoteConnectionConstants.java @@ -31,9 +31,6 @@ public class ZygoteConnectionConstants { */ public static final int CONNECTION_TIMEOUT_MILLIS = 1000; - /** max number of arguments that a connection can specify */ - public static final int MAX_ZYGOTE_ARGC = 1024; - /** * Wait time for a wrapped app to report back its pid. * diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index ef1c50f43681..fe87b64940fb 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -65,6 +65,7 @@ import dalvik.system.ZygoteHooks; import libcore.io.IoUtils; import java.io.BufferedReader; +import java.io.EOFException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -779,7 +780,13 @@ public class ZygoteInit { int pid; try { - parsedArgs = new ZygoteArguments(args); + ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args); + try { + parsedArgs = ZygoteArguments.getInstance(commandBuffer); + } catch (EOFException e) { + throw new AssertionError("Unexpected argument error for forking system server", e); + } + commandBuffer.close(); Zygote.applyDebuggerSystemProperty(parsedArgs); Zygote.applyInvokeWithSystemProperty(parsedArgs); @@ -858,7 +865,7 @@ public class ZygoteInit { * into new processes are required to either set the priority to the default value or terminate * before executing any non-system code. The native side of this occurs in SpecializeCommon, * while the Java Language priority is changed in ZygoteInit.handleSystemServerProcess, - * ZygoteConnection.handleChildProc, and Zygote.usapMain. + * ZygoteConnection.handleChildProc, and Zygote.childMain. * * @param argv Command line arguments used to specify the Zygote's configuration. */ diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java index 585ddf6ddf98..f71b31493035 100644 --- a/core/java/com/android/internal/os/ZygoteServer.java +++ b/core/java/com/android/internal/os/ZygoteServer.java @@ -337,7 +337,7 @@ class ZygoteServer { * @param sessionSocketRawFDs Anonymous session sockets that are currently open * @return In the Zygote process this function will always return null; in unspecialized app * processes this function will return a Runnable object representing the new - * application that is passed up from usapMain. + * application that is passed up from childMain (the usap's main wait loop). */ Runnable fillUsapPool(int[] sessionSocketRawFDs, boolean isPriorityRefill) { @@ -420,6 +420,7 @@ class ZygoteServer { * Runs the zygote process's select loop. Accepts new connections as * they happen, and reads commands from connections one spawn-request's * worth at a time. + * @param abiList list of ABIs supported by this zygote. */ Runnable runSelectLoop(String abiList) { ArrayList<FileDescriptor> socketFDs = new ArrayList<>(); @@ -537,22 +538,23 @@ class ZygoteServer { if (pollIndex == 0) { // Zygote server socket - ZygoteConnection newPeer = acceptCommandPeer(abiList); peers.add(newPeer); socketFDs.add(newPeer.getFileDescriptor()); - } else if (pollIndex < usapPoolEventFDIndex) { // Session socket accepted from the Zygote server socket try { ZygoteConnection connection = peers.get(pollIndex); - final Runnable command = connection.processOneCommand(this); + boolean multipleForksOK = !isUsapPoolEnabled() + && ZygoteHooks.indefiniteThreadSuspensionOK(); + final Runnable command = + connection.processCommand(this, multipleForksOK); // TODO (chriswailes): Is this extra check necessary? if (mIsForkChild) { // We're in the child. We should always have a command to run at - // this stage if processOneCommand hasn't called "exec". + // this stage if processCommand hasn't called "exec". if (command == null) { throw new IllegalStateException("command == null"); } @@ -565,7 +567,7 @@ class ZygoteServer { } // We don't know whether the remote side of the socket was closed or - // not until we attempt to read from it from processOneCommand. This + // not until we attempt to read from it from processCommand. This // shows up as a regular POLLIN event in our regular processing // loop. if (connection.isClosedByPeer()) { diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 2a73dacbc94a..47e696a86334 100644 --- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -93,5 +93,5 @@ interface ITelephonyRegistry { void notifyBarringInfoChanged(int slotIndex, int subId, in BarringInfo barringInfo); void notifyPhysicalChannelConfigForSubscriber(in int subId, in List<PhysicalChannelConfig> configs); - void notifyDataEnabled(boolean enabled, int reason); + void notifyDataEnabled(in int phoneId, int subId, boolean enabled, int reason); } diff --git a/core/java/com/android/internal/view/OWNERS b/core/java/com/android/internal/view/OWNERS index 851d1f37522a..eb2478f6550a 100644 --- a/core/java/com/android/internal/view/OWNERS +++ b/core/java/com/android/internal/view/OWNERS @@ -18,3 +18,7 @@ per-file AppearanceRegion = file:/services/core/java/com/android/server/wm/OWNER per-file BaseIWIndow.java = file:/services/core/java/com/android/server/wm/OWNERS per-file RotationPolicy.java = file:/services/core/java/com/android/server/wm/OWNERS per-file WindowManagerPolicyThread.java = file:/services/core/java/com/android/server/wm/OWNERS + +# Scroll Capture +per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS +per-file *CaptureHelper*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS diff --git a/core/java/com/android/server/OWNERS b/core/java/com/android/server/OWNERS new file mode 100644 index 000000000000..1262925447b9 --- /dev/null +++ b/core/java/com/android/server/OWNERS @@ -0,0 +1 @@ +per-file SystemConfig.java = toddke@google.com diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 0d05a6b82d36..e58ad79de89e 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -206,6 +206,7 @@ cc_library_shared { "com_android_internal_os_KernelCpuUidBpfMapReader.cpp", "com_android_internal_os_KernelSingleUidTimeReader.cpp", "com_android_internal_os_Zygote.cpp", + "com_android_internal_os_ZygoteCommandBuffer.cpp", "com_android_internal_os_ZygoteInit.cpp", "hwbinder/EphemeralStorage.cpp", "fd_utils.cpp", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 3198cb1b8140..c01f741862b1 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -193,6 +193,7 @@ extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env); extern int register_com_android_internal_os_KernelCpuUidBpfMapReader(JNIEnv *env); extern int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *env); extern int register_com_android_internal_os_Zygote(JNIEnv *env); +extern int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv *env); extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env); extern int register_com_android_internal_util_VirtualRefBasePtr(JNIEnv *env); @@ -1524,6 +1525,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_com_android_internal_net_NetworkUtilsInternal), REG_JNI(register_com_android_internal_os_ClassLoaderFactory), REG_JNI(register_com_android_internal_os_Zygote), + REG_JNI(register_com_android_internal_os_ZygoteCommandBuffer), REG_JNI(register_com_android_internal_os_ZygoteInit), REG_JNI(register_com_android_internal_util_VirtualRefBasePtr), REG_JNI(register_android_hardware_Camera), diff --git a/core/jni/OWNERS b/core/jni/OWNERS index 35d1d7bd7946..19c6a625646e 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -42,6 +42,9 @@ per-file android_os_HwParcel* = file:platform/system/libhwbinder:/OWNERS per-file android_os_HwRemoteBinder* = file:platform/system/libhwbinder:/OWNERS per-file EphemeralStorage* = file:platform/system/libhwbinder:/OWNERS +# Sensor +per-file android_hardware_SensorManager* = arthuri@google.com, bduddie@google.com, stange@google.com + per-file *Zygote* = file:/ZYGOTE_OWNERS per-file Android.bp = file:platform/build/soong:/OWNERS per-file android_animation_* = file:/core/java/android/animation/OWNERS diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 903ecaef4938..bcd203b6ca77 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -17,6 +17,8 @@ #define LOG_TAG "Zygote" #define ATRACE_TAG ATRACE_TAG_DALVIK +#include "com_android_internal_os_Zygote.h" + #include <async_safe/log.h> // sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc @@ -91,19 +93,6 @@ #include "nativebridge/native_bridge.h" -/* Functions in the callchain during the fork shall not be protected with - Armv8.3-A Pointer Authentication, otherwise child will not be able to return. */ -#ifdef __ARM_FEATURE_PAC_DEFAULT -#ifdef __ARM_FEATURE_BTI_DEFAULT -#define NO_PAC_FUNC __attribute__((target("branch-protection=bti"))) -#else -#define NO_PAC_FUNC __attribute__((target("branch-protection=none"))) -#endif /* __ARM_FEATURE_BTI_DEFAULT */ -#else /* !__ARM_FEATURE_PAC_DEFAULT */ -#define NO_PAC_FUNC -#endif /* __ARM_FEATURE_PAC_DEFAULT */ - - namespace { // TODO (chriswailes): Add a function to initialize native Zygote data. @@ -118,8 +107,7 @@ using android::base::StringPrintf; using android::base::WriteStringToFile; using android::base::GetBoolProperty; -#define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \ - append(StringPrintf(__VA_ARGS__)) +using android::zygote::ZygoteFailure; // This type is duplicated in fd_utils.h typedef const std::function<void(std::string)>& fail_fn_t; @@ -215,7 +203,7 @@ class UsapTableEntry { static constexpr EntryStorage INVALID_ENTRY_VALUE = {-1, -1}; std::atomic<EntryStorage> mStorage; - static_assert(decltype(mStorage)::is_always_lock_free); + static_assert(decltype(mStorage)::is_always_lock_free); // Accessed from signal handler. public: constexpr UsapTableEntry() : mStorage(INVALID_ENTRY_VALUE) {} @@ -356,6 +344,7 @@ enum RuntimeFlags : uint32_t { GWP_ASAN_LEVEL_NEVER = 0 << 21, GWP_ASAN_LEVEL_LOTTERY = 1 << 21, GWP_ASAN_LEVEL_ALWAYS = 2 << 21, + NATIVE_HEAP_ZERO_INIT = 1 << 23, }; enum UnsolicitedZygoteMessageTypes : uint32_t { @@ -942,36 +931,6 @@ void SetThreadName(const std::string& thread_name) { } /** - * A failure function used to report fatal errors to the managed runtime. This - * function is often curried with the process name information and then passed - * to called functions. - * - * @param env Managed runtime environment - * @param process_name A native representation of the process name - * @param managed_process_name A managed representation of the process name - * @param msg The error message to be reported - */ -[[noreturn]] -static void ZygoteFailure(JNIEnv* env, - const char* process_name, - jstring managed_process_name, - const std::string& msg) { - std::unique_ptr<ScopedUtfChars> scoped_managed_process_name_ptr = nullptr; - if (managed_process_name != nullptr) { - scoped_managed_process_name_ptr.reset(new ScopedUtfChars(env, managed_process_name)); - if (scoped_managed_process_name_ptr->c_str() != nullptr) { - process_name = scoped_managed_process_name_ptr->c_str(); - } - } - - const std::string& error_msg = - (process_name == nullptr) ? msg : StringPrintf("(%s) %s", process_name, msg.c_str()); - - env->FatalError(error_msg.c_str()); - __builtin_unreachable(); -} - -/** * A helper method for converting managed strings to native strings. A fatal * error is generated if a problem is encountered in extracting a non-null * string. @@ -1098,86 +1057,6 @@ static void PAuthKeyChange(JNIEnv* env) { #endif } -// Utility routine to fork a process from the zygote. -NO_PAC_FUNC -static pid_t ForkCommon(JNIEnv* env, bool is_system_server, - const std::vector<int>& fds_to_close, - const std::vector<int>& fds_to_ignore, - bool is_priority_fork) { - SetSignalHandlers(); - - // Curry a failure function. - auto fail_fn = std::bind(ZygoteFailure, env, is_system_server ? "system_server" : "zygote", - nullptr, _1); - - // Temporarily block SIGCHLD during forks. The SIGCHLD handler might - // log, which would result in the logging FDs we close being reopened. - // This would cause failures because the FDs are not allowlisted. - // - // Note that the zygote process is single threaded at this point. - BlockSignal(SIGCHLD, fail_fn); - - // Close any logging related FDs before we start evaluating the list of - // file descriptors. - __android_log_close(); - AStatsSocket_close(); - - // If this is the first fork for this zygote, create the open FD table. If - // it isn't, we just need to check whether the list of open files has changed - // (and it shouldn't in the normal case). - if (gOpenFdTable == nullptr) { - gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, fail_fn); - } else { - gOpenFdTable->Restat(fds_to_ignore, fail_fn); - } - - android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level(); - - // Purge unused native memory in an attempt to reduce the amount of false - // sharing with the child process. By reducing the size of the libc_malloc - // region shared with the child process we reduce the number of pages that - // transition to the private-dirty state when malloc adjusts the meta-data - // on each of the pages it is managing after the fork. - mallopt(M_PURGE, 0); - - pid_t pid = fork(); - - if (pid == 0) { - if (is_priority_fork) { - setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX); - } else { - setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN); - } - - // The child process. - PAuthKeyChange(env); - PreApplicationInit(); - - // Clean up any descriptors which must be closed immediately - DetachDescriptors(env, fds_to_close, fail_fn); - - // Invalidate the entries in the USAP table. - ClearUsapTable(); - - // Re-open all remaining open file descriptors so that they aren't shared - // with the zygote across a fork. - gOpenFdTable->ReopenOrDetach(fail_fn); - - // Turn fdsan back on. - android_fdsan_set_error_level(fdsan_error_level); - - // Reset the fd to the unsolicited zygote socket - gSystemServerSocketFd = -1; - } else { - ALOGD("Forked child process %d", pid); - } - - // We blocked SIGCHLD prior to a fork, we unblock it here. - UnblockSignal(SIGCHLD, fail_fn); - - return pid; -} - // Create an app data directory over tmpfs overlayed CE / DE storage, and bind mount it // from the actual app data directory in data mirror. static bool createAndMountAppData(std::string_view package_name, @@ -1804,15 +1683,20 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, } mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level); + // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime. + runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK; + // Avoid heap zero initialization for applications without MTE. Zero init may // cause app compat problems, use more memory, or reduce performance. While it // would be nice to have them for apps, we will have to wait until they are // proven out, have more efficient hardware, and/or apply them only to new // applications. - mallopt(M_BIONIC_ZERO_INIT, 0); + if (!(runtime_flags & RuntimeFlags::NATIVE_HEAP_ZERO_INIT)) { + mallopt(M_BIONIC_ZERO_INIT, 0); + } // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime. - runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK; + runtime_flags &= ~RuntimeFlags::NATIVE_HEAP_ZERO_INIT; bool forceEnableGwpAsan = false; switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) { @@ -1993,9 +1877,10 @@ static void AddUsapTableEntry(pid_t usap_pid, int read_pipe_fd) { static int sUsapTableInsertIndex = 0; int search_index = sUsapTableInsertIndex; - do { if (gUsapTable[search_index].SetIfInvalid(usap_pid, read_pipe_fd)) { + ++gUsapPoolCount; + // Start our next search right after where we finished this one. sUsapTableInsertIndex = (search_index + 1) % gUsapTable.size(); @@ -2013,7 +1898,7 @@ static void AddUsapTableEntry(pid_t usap_pid, int read_pipe_fd) { /** * Invalidates the entry in the USAPTable corresponding to the provided * process ID if it is present. If an entry was removed the USAP pool - * count is decremented. + * count is decremented. May be called from signal handler. * * @param usap_pid Process ID of the USAP entry to invalidate * @return True if an entry was invalidated; false otherwise @@ -2089,6 +1974,121 @@ static void UnmountStorageOnInit(JNIEnv* env) { namespace android { +/** + * A failure function used to report fatal errors to the managed runtime. This + * function is often curried with the process name information and then passed + * to called functions. + * + * @param env Managed runtime environment + * @param process_name A native representation of the process name + * @param managed_process_name A managed representation of the process name + * @param msg The error message to be reported + */ +[[noreturn]] +void zygote::ZygoteFailure(JNIEnv* env, + const char* process_name, + jstring managed_process_name, + const std::string& msg) { + std::unique_ptr<ScopedUtfChars> scoped_managed_process_name_ptr = nullptr; + if (managed_process_name != nullptr) { + scoped_managed_process_name_ptr.reset(new ScopedUtfChars(env, managed_process_name)); + if (scoped_managed_process_name_ptr->c_str() != nullptr) { + process_name = scoped_managed_process_name_ptr->c_str(); + } + } + + const std::string& error_msg = + (process_name == nullptr || process_name[0] == '\0') ? + msg : StringPrintf("(%s) %s", process_name, msg.c_str()); + + env->FatalError(error_msg.c_str()); + __builtin_unreachable(); +} + +// Utility routine to fork a process from the zygote. +NO_PAC_FUNC +pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server, + const std::vector<int>& fds_to_close, + const std::vector<int>& fds_to_ignore, + bool is_priority_fork, + bool purge) { + SetSignalHandlers(); + + // Curry a failure function. + auto fail_fn = std::bind(zygote::ZygoteFailure, env, + is_system_server ? "system_server" : "zygote", + nullptr, _1); + + // Temporarily block SIGCHLD during forks. The SIGCHLD handler might + // log, which would result in the logging FDs we close being reopened. + // This would cause failures because the FDs are not allowlisted. + // + // Note that the zygote process is single threaded at this point. + BlockSignal(SIGCHLD, fail_fn); + + // Close any logging related FDs before we start evaluating the list of + // file descriptors. + __android_log_close(); + AStatsSocket_close(); + + // If this is the first fork for this zygote, create the open FD table. If + // it isn't, we just need to check whether the list of open files has changed + // (and it shouldn't in the normal case). + if (gOpenFdTable == nullptr) { + gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, fail_fn); + } else { + gOpenFdTable->Restat(fds_to_ignore, fail_fn); + } + + android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level(); + + if (purge) { + // Purge unused native memory in an attempt to reduce the amount of false + // sharing with the child process. By reducing the size of the libc_malloc + // region shared with the child process we reduce the number of pages that + // transition to the private-dirty state when malloc adjusts the meta-data + // on each of the pages it is managing after the fork. + mallopt(M_PURGE, 0); + } + + pid_t pid = fork(); + + if (pid == 0) { + if (is_priority_fork) { + setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX); + } else { + setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN); + } + + // The child process. + PAuthKeyChange(env); + PreApplicationInit(); + + // Clean up any descriptors which must be closed immediately + DetachDescriptors(env, fds_to_close, fail_fn); + + // Invalidate the entries in the USAP table. + ClearUsapTable(); + + // Re-open all remaining open file descriptors so that they aren't shared + // with the zygote across a fork. + gOpenFdTable->ReopenOrDetach(fail_fn); + + // Turn fdsan back on. + android_fdsan_set_error_level(fdsan_error_level); + + // Reset the fd to the unsolicited zygote socket + gSystemServerSocketFd = -1; + } else { + ALOGD("Forked child process %d", pid); + } + + // We blocked SIGCHLD prior to a fork, we unblock it here. + UnblockSignal(SIGCHLD, fail_fn); + + return pid; +} + static void com_android_internal_os_Zygote_nativePreApplicationInit(JNIEnv*, jclass) { PreApplicationInit(); } @@ -2105,7 +2105,8 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); if (UNLIKELY(managed_fds_to_close == nullptr)) { - ZygoteFailure(env, "zygote", nice_name, "Zygote received a null fds_to_close vector."); + zygote::ZygoteFailure(env, "zygote", nice_name, + "Zygote received a null fds_to_close vector."); } std::vector<int> fds_to_close = @@ -2131,7 +2132,7 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( fds_to_ignore.push_back(gSystemServerSocketFd); } - pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore, true); + pid_t pid = zygote::ForkCommon(env, false, fds_to_close, fds_to_ignore, true); if (pid == 0) { SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, @@ -2166,10 +2167,10 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( fds_to_ignore.push_back(gSystemServerSocketFd); } - pid_t pid = ForkCommon(env, true, - fds_to_close, - fds_to_ignore, - true); + pid_t pid = zygote::ForkCommon(env, true, + fds_to_close, + fds_to_ignore, + true); if (pid == 0) { // System server prcoess does not need data isolation so no need to // know pkg_data_info_list. @@ -2209,58 +2210,74 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( * ensuring proper file descriptor hygiene. * * @param env Managed runtime environment - * @param read_pipe_fd The read FD for the USAP reporting pipe. Manually closed by blastlas - * in managed code. + * @param read_pipe_fd The read FD for the USAP reporting pipe. Manually closed by the child + * in managed code. -1 indicates none. * @param write_pipe_fd The write FD for the USAP reporting pipe. Manually closed by the - * zygote in managed code. + * zygote in managed code. -1 indicates none. * @param managed_session_socket_fds A list of anonymous session sockets that must be ignored by * the FD hygiene code and automatically "closed" in the new USAP. + * @param args_known Arguments for specialization are available; no need to read from a socket * @param is_priority_fork Controls the nice level assigned to the newly created process - * @return + * @return child pid in the parent, 0 in the child */ NO_PAC_FUNC -static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env, - jclass, - jint read_pipe_fd, - jint write_pipe_fd, - jintArray managed_session_socket_fds, - jboolean is_priority_fork) { - std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()), - fds_to_ignore(fds_to_close); - +static jint com_android_internal_os_Zygote_nativeForkApp(JNIEnv* env, + jclass, + jint read_pipe_fd, + jint write_pipe_fd, + jintArray managed_session_socket_fds, + jboolean args_known, + jboolean is_priority_fork) { std::vector<int> session_socket_fds = ExtractJIntArray(env, "USAP", nullptr, managed_session_socket_fds) .value_or(std::vector<int>()); + return zygote::forkApp(env, read_pipe_fd, write_pipe_fd, session_socket_fds, + args_known == JNI_TRUE, is_priority_fork == JNI_TRUE, true); +} - // The USAP Pool Event FD is created during the initialization of the - // USAP pool and should always be valid here. +NO_PAC_FUNC +int zygote::forkApp(JNIEnv* env, + int read_pipe_fd, + int write_pipe_fd, + const std::vector<int>& session_socket_fds, + bool args_known, + bool is_priority_fork, + bool purge) { + + std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()), + fds_to_ignore(fds_to_close); fds_to_close.push_back(gZygoteSocketFD); - fds_to_close.push_back(gUsapPoolEventFD); - fds_to_close.insert(fds_to_close.end(), session_socket_fds.begin(), session_socket_fds.end()); if (gSystemServerSocketFd != -1) { fds_to_close.push_back(gSystemServerSocketFd); } + if (args_known) { + fds_to_close.push_back(gUsapPoolSocketFD); + } + fds_to_close.insert(fds_to_close.end(), session_socket_fds.begin(), session_socket_fds.end()); - fds_to_ignore.push_back(gZygoteSocketFD); fds_to_ignore.push_back(gUsapPoolSocketFD); - fds_to_ignore.push_back(gUsapPoolEventFD); - fds_to_ignore.push_back(read_pipe_fd); - fds_to_ignore.push_back(write_pipe_fd); + fds_to_ignore.push_back(gZygoteSocketFD); + if (read_pipe_fd != -1) { + fds_to_ignore.push_back(read_pipe_fd); + } + if (write_pipe_fd != -1) { + fds_to_ignore.push_back(write_pipe_fd); + } fds_to_ignore.insert(fds_to_ignore.end(), session_socket_fds.begin(), session_socket_fds.end()); + + if (gUsapPoolEventFD != -1) { + fds_to_close.push_back(gUsapPoolEventFD); + fds_to_ignore.push_back(gUsapPoolEventFD); + } if (gSystemServerSocketFd != -1) { + if (args_known) { + fds_to_close.push_back(gSystemServerSocketFd); + } fds_to_ignore.push_back(gSystemServerSocketFd); } - - pid_t usap_pid = ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore, - is_priority_fork == JNI_TRUE); - - if (usap_pid != 0) { - ++gUsapPoolCount; - AddUsapTableEntry(usap_pid, read_pipe_fd); - } - - return usap_pid; + return zygote::ForkCommon(env, /* is_system_server= */ false, fds_to_close, + fds_to_ignore, is_priority_fork == JNI_TRUE, purge); } static void com_android_internal_os_Zygote_nativeAllowFileAcrossFork( @@ -2374,7 +2391,7 @@ static void com_android_internal_os_Zygote_nativeInitNativeState(JNIEnv* env, jc */ if (!SetTaskProfiles(0, {})) { - ZygoteFailure(env, "zygote", nullptr, "Zygote SetTaskProfiles failed"); + zygote::ZygoteFailure(env, "zygote", nullptr, "Zygote SetTaskProfiles failed"); } } @@ -2392,15 +2409,21 @@ static jintArray com_android_internal_os_Zygote_nativeGetUsapPipeFDs(JNIEnv* env return managed_usap_fds; } +/* + * Add the given pid and file descriptor to the Usap table. CriticalNative method. + */ +static void com_android_internal_os_Zygote_nativeAddUsapTableEntry(jint pid, jint read_pipe_fd) { + AddUsapTableEntry(pid, read_pipe_fd); +} + /** - * A JNI wrapper around RemoveUsapTableEntry. + * A JNI wrapper around RemoveUsapTableEntry. CriticalNative method. * * @param env Managed runtime environment * @param usap_pid Process ID of the USAP entry to invalidate * @return True if an entry was invalidated; false otherwise. */ -static jboolean com_android_internal_os_Zygote_nativeRemoveUsapTableEntry(JNIEnv* env, jclass, - jint usap_pid) { +static jboolean com_android_internal_os_Zygote_nativeRemoveUsapTableEntry(jint usap_pid) { return RemoveUsapTableEntry(usap_pid); } @@ -2415,7 +2438,8 @@ static jboolean com_android_internal_os_Zygote_nativeRemoveUsapTableEntry(JNIEnv static jint com_android_internal_os_Zygote_nativeGetUsapPoolEventFD(JNIEnv* env, jclass) { if (gUsapPoolEventFD == -1) { if ((gUsapPoolEventFD = eventfd(0, 0)) == -1) { - ZygoteFailure(env, "zygote", nullptr, StringPrintf("Unable to create eventfd: %s", strerror(errno))); + zygote::ZygoteFailure(env, "zygote", nullptr, + StringPrintf("Unable to create eventfd: %s", strerror(errno))); } } @@ -2458,12 +2482,12 @@ static void com_android_internal_os_Zygote_nativeEmptyUsapPool(JNIEnv* env, jcla } static void com_android_internal_os_Zygote_nativeBlockSigTerm(JNIEnv* env, jclass) { - auto fail_fn = std::bind(ZygoteFailure, env, "usap", nullptr, _1); + auto fail_fn = std::bind(zygote::ZygoteFailure, env, "usap", nullptr, _1); BlockSignal(SIGTERM, fail_fn); } static void com_android_internal_os_Zygote_nativeUnblockSigTerm(JNIEnv* env, jclass) { - auto fail_fn = std::bind(ZygoteFailure, env, "usap", nullptr, _1); + auto fail_fn = std::bind(zygote::ZygoteFailure, env, "usap", nullptr, _1); UnblockSignal(SIGTERM, fail_fn); } @@ -2569,7 +2593,10 @@ static const JNINativeMethod gMethods[] = { (void*)com_android_internal_os_Zygote_nativePreApplicationInit}, {"nativeInstallSeccompUidGidFilter", "(II)V", (void*)com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter}, - {"nativeForkUsap", "(II[IZ)I", (void*)com_android_internal_os_Zygote_nativeForkUsap}, + {"nativeForkApp", "(II[IZZ)I", (void*)com_android_internal_os_Zygote_nativeForkApp}, + // @CriticalNative + {"nativeAddUsapTableEntry", "(II)V", + (void*)com_android_internal_os_Zygote_nativeAddUsapTableEntry}, {"nativeSpecializeAppProcess", "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/" "String;Z[Ljava/lang/String;[Ljava/lang/String;ZZ)V", @@ -2578,6 +2605,10 @@ static const JNINativeMethod gMethods[] = { (void*)com_android_internal_os_Zygote_nativeInitNativeState}, {"nativeGetUsapPipeFDs", "()[I", (void*)com_android_internal_os_Zygote_nativeGetUsapPipeFDs}, + // @CriticalNative + {"nativeAddUsapTableEntry", "(II)V", + (void*)com_android_internal_os_Zygote_nativeAddUsapTableEntry}, + // @CriticalNative {"nativeRemoveUsapTableEntry", "(I)Z", (void*)com_android_internal_os_Zygote_nativeRemoveUsapTableEntry}, {"nativeGetUsapPoolEventFD", "()I", diff --git a/core/jni/com_android_internal_os_Zygote.h b/core/jni/com_android_internal_os_Zygote.h new file mode 100644 index 000000000000..d2da91476bc7 --- /dev/null +++ b/core/jni/com_android_internal_os_Zygote.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2008 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. + */ + +#ifndef _COM_ANDROID_INTERNAL_OS_ZYGOTE_H +#define _COM_ANDROID_INTERNAL_OS_ZYGOTE_H + +#define LOG_TAG "Zygote" +#define ATRACE_TAG ATRACE_TAG_DALVIK + +/* Functions in the callchain during the fork shall not be protected with + Armv8.3-A Pointer Authentication, otherwise child will not be able to return. */ +#ifdef __ARM_FEATURE_PAC_DEFAULT +#ifdef __ARM_FEATURE_BTI_DEFAULT +#define NO_PAC_FUNC __attribute__((target("branch-protection=bti"))) +#else +#define NO_PAC_FUNC __attribute__((target("branch-protection=none"))) +#endif /* __ARM_FEATURE_BTI_DEFAULT */ +#else /* !__ARM_FEATURE_PAC_DEFAULT */ +#define NO_PAC_FUNC +#endif /* __ARM_FEATURE_PAC_DEFAULT */ + +#include <jni.h> +#include <vector> +#include <android-base/stringprintf.h> + +#define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \ + append(StringPrintf(__VA_ARGS__)) + +namespace android { +namespace zygote { + +NO_PAC_FUNC +pid_t ForkCommon(JNIEnv* env,bool is_system_server, + const std::vector<int>& fds_to_close, + const std::vector<int>& fds_to_ignore, + bool is_priority_fork, + bool purge = true); + +/** + * Fork a process. The pipe fds are used for usap communication, or -1 in + * other cases. Session_socket_fds are FDs used for zygote communication that must be dealt + * with hygienically, but are not otherwise used here. Args_known indicates that the process + * will be immediately specialized with arguments that are already known, so no usap + * communication is required. Is_priority_fork should be true if this is on the app startup + * critical path. Purge specifies that unused pages should be purged before the fork. + */ +NO_PAC_FUNC +int forkApp(JNIEnv* env, + int read_pipe_fd, + int write_pipe_fd, + const std::vector<int>& session_socket_fds, + bool args_known, + bool is_priority_fork, + bool purge); + +[[noreturn]] +void ZygoteFailure(JNIEnv* env, + const char* process_name, + jstring managed_process_name, + const std::string& msg); + +} // namespace zygote +} // namespace android + +#endif // _COM_ANDROID_INTERNAL_OS_ZYGOTE_ diff --git a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp new file mode 100644 index 000000000000..011e8f8f1b8c --- /dev/null +++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp @@ -0,0 +1,512 @@ +/* + * 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. + */ + +#include "com_android_internal_os_Zygote.h" + +#include <algorithm> +#include <android-base/logging.h> +#include <async_safe/log.h> +#include <cctype> +#include <chrono> +#include <core_jni_helpers.h> +#include <errno.h> +#include <fcntl.h> +#include <jni.h> +#include <nativehelper/JNIHelp.h> +#include <optional> +#include <poll.h> +#include <unistd.h> +#include <utility> +#include <utils/misc.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <vector> + +namespace android { + +using namespace std::placeholders; +using android::base::StringPrintf; +using android::zygote::ZygoteFailure; + +// WARNING: Knows a little about the wire protocol used to communicate with Zygote. +// TODO: Fix error handling. + +constexpr size_t MAX_COMMAND_BYTES = 12200; +constexpr size_t NICE_NAME_BYTES = 50; + +// A buffer optionally bundled with a file descriptor from which we can fill it. +// Does not own the file descriptor; destroying a NativeCommandBuffer does not +// close the descriptor. +class NativeCommandBuffer { + public: + NativeCommandBuffer(int sourceFd): mEnd(0), mNext(0), mLinesLeft(0), mFd(sourceFd) {} + + // Read mNext line from mFd, filling mBuffer from file descriptor, as needed. + // Return a pair of pointers pointing to the first character, and one past the + // mEnd of the line, i.e. at the newline. Returns nothing on failure. + template<class FailFn> + std::optional<std::pair<char*, char*>> readLine(FailFn fail_fn) { + char* result = mBuffer + mNext; + while (true) { + if (mNext == mEnd) { + if (mEnd == MAX_COMMAND_BYTES) { + return {}; + } + if (mFd == -1) { + fail_fn("ZygoteCommandBuffer.readLine attempted to read from mFd -1"); + } + ssize_t nread = TEMP_FAILURE_RETRY(read(mFd, mBuffer + mEnd, MAX_COMMAND_BYTES - mEnd)); + if (nread <= 0) { + if (nread == 0) { + return {}; + } + fail_fn(CREATE_ERROR("session socket read failed: %s", strerror(errno))); + } else if (nread == MAX_COMMAND_BYTES - mEnd) { + // This is pessimistic by one character, but close enough. + fail_fn("ZygoteCommandBuffer overflowed: command too long"); + } + mEnd += nread; + } + // UTF-8 does not allow newline to occur as part of a multibyte character. + char* nl = static_cast<char *>(memchr(mBuffer + mNext, '\n', mEnd - mNext)); + if (nl == nullptr) { + mNext = mEnd; + } else { + mNext = nl - mBuffer + 1; + if (--mLinesLeft < 0) { + fail_fn("ZygoteCommandBuffer.readLine attempted to read past mEnd of command"); + } + return std::make_pair(result, nl); + } + } + } + + void reset() { + mNext = 0; + } + + // Make sure the current command is fully buffered, without reading past the current command. + template<class FailFn> + void readAllLines(FailFn fail_fn) { + while (mLinesLeft > 0) { + readLine(fail_fn); + } + } + + void clear() { + // Don't bother to actually clear the buffer; it'll be unmapped in the child anyway. + reset(); + mNiceName[0] = '\0'; + mEnd = 0; + } + + // Insert line into the mBuffer. Checks that the mBuffer is not associated with an mFd. + // Implicitly adds newline separators. Allows mBuffer contents to be explicitly set. + void insert(const char* line, size_t lineLen) { + DCHECK(mFd == -1); + CHECK(mEnd + lineLen < MAX_COMMAND_BYTES); + strncpy(mBuffer + mEnd, line, lineLen); + mBuffer[mEnd + lineLen] = '\n'; + mEnd += lineLen + 1; + } + + // Clear mBuffer, start reading new command, return the number of arguments, leaving mBuffer + // positioned at the beginning of first argument. Return 0 on EOF. + template<class FailFn> + int getCount(FailFn fail_fn) { + mLinesLeft = 1; + auto line = readLine(fail_fn); + if (!line.has_value()) { + return 0; + } + char* countString = line.value().first; // Newline terminated. + long nArgs = atol(countString); + if (nArgs <= 0 || nArgs >= MAX_COMMAND_BYTES / 2) { + fail_fn(CREATE_ERROR("Unreasonable argument count %ld", nArgs)); + } + mLinesLeft = nArgs; + return static_cast<int>(nArgs); + } + + // Is the mBuffer a simple fork command? + // We disallow request to wrap the child process, child zygotes, anything that + // mentions capabilities or requests uid < minUid. + // We insist that --setuid and --setgid arguments are explicitly included and that the + // command starts with --runtime-args. + // Assumes we are positioned at the beginning of the command after the argument count, + // and leaves the position at some indeterminate position in the buffer. + // As a side effect, this sets mNiceName to a non-empty string, if possible. + template<class FailFn> + bool isSimpleForkCommand(int minUid, FailFn fail_fn) { + if (mLinesLeft <= 0 || mLinesLeft >= MAX_COMMAND_BYTES / 2) { + return false; + } + static const char* RUNTIME_ARGS = "--runtime-args"; + static const char* INVOKE_WITH = "--invoke-with"; + static const char* CHILD_ZYGOTE = "--start-child-zygote"; + static const char* SETUID = "--setuid="; + static const char* SETGID = "--setgid="; + static const char* CAPABILITIES = "--capabilities"; + static const char* NICE_NAME = "--nice-name="; + static const size_t RA_LENGTH = strlen(RUNTIME_ARGS); + static const size_t IW_LENGTH = strlen(INVOKE_WITH); + static const size_t CZ_LENGTH = strlen(CHILD_ZYGOTE); + static const size_t SU_LENGTH = strlen(SETUID); + static const size_t SG_LENGTH = strlen(SETGID); + static const size_t CA_LENGTH = strlen(CAPABILITIES); + static const size_t NN_LENGTH = strlen(NICE_NAME); + + bool saw_setuid = false, saw_setgid = false; + bool saw_runtime_args = false; + + while (mLinesLeft > 0) { + auto read_result = readLine(fail_fn); + if (!read_result.has_value()) { + return false; + } + auto [arg_start, arg_end] = read_result.value(); + if (arg_end - arg_start == RA_LENGTH + && strncmp(arg_start, RUNTIME_ARGS, RA_LENGTH) == 0) { + saw_runtime_args = true; + continue; + } + if (arg_end - arg_start >= NN_LENGTH + && strncmp(arg_start, NICE_NAME, NN_LENGTH) == 0) { + size_t name_len = arg_end - (arg_start + NN_LENGTH); + size_t copy_len = std::min(name_len, NICE_NAME_BYTES - 1); + memcpy(mNiceName, arg_start + NN_LENGTH, copy_len); + mNiceName[copy_len] = '\0'; + continue; + } + if (arg_end - arg_start == IW_LENGTH + && strncmp(arg_start, INVOKE_WITH, IW_LENGTH) == 0) { + // This also removes the need for invoke-with security checks here. + return false; + } + if (arg_end - arg_start == CZ_LENGTH + && strncmp(arg_start, CHILD_ZYGOTE, CZ_LENGTH) == 0) { + return false; + } + if (arg_end - arg_start >= CA_LENGTH + && strncmp(arg_start, CAPABILITIES, CA_LENGTH) == 0) { + return false; + } + if (arg_end - arg_start >= SU_LENGTH + && strncmp(arg_start, SETUID, SU_LENGTH) == 0) { + int uid = digitsVal(arg_start + SU_LENGTH, arg_end); + if (uid < minUid) { + return false; + } + saw_setuid = true; + continue; + } + if (arg_end - arg_start >= SG_LENGTH + && strncmp(arg_start, SETGID, SG_LENGTH) == 0) { + int gid = digitsVal(arg_start + SG_LENGTH, arg_end); + if (gid == -1) { + return false; + } + saw_setgid = true; + } + } + return saw_runtime_args && saw_setuid && saw_setgid; + } + + void setFd(int new_fd) { + mFd = new_fd; + } + + int getFd() const { + return mFd; + } + + const char* niceNameAddr() const { + return mNiceName; + } + + // Debug only: + void logState() const { + ALOGD("mbuffer starts with %c%c, nice name is %s, " + "mEnd = %u, mNext = %u, mLinesLeft = %d, mFd = %d", + mBuffer[0], (mBuffer[1] == '\n' ? ' ' : mBuffer[1]), + niceNameAddr(), + static_cast<unsigned>(mEnd), static_cast<unsigned>(mNext), + static_cast<int>(mLinesLeft), mFd); + } + + private: + // Picky version of atoi(). No sign or unexpected characters allowed. Return -1 on failure. + static int digitsVal(char* start, char* end) { + int result = 0; + if (end - start > 6) { + return -1; + } + for (char* dp = start; dp < end; ++dp) { + if (*dp < '0' || *dp > '9') { + ALOGW("Argument failed integer format check"); + return -1; + } + result = 10 * result + (*dp - '0'); + } + return result; + } + + uint32_t mEnd; // Index of first empty byte in the mBuffer. + uint32_t mNext; // Index of first character past last line returned by readLine. + int32_t mLinesLeft; // Lines in current command that haven't yet been read. + int mFd; // Open file descriptor from which we can read more. -1 if none. + char mNiceName[NICE_NAME_BYTES]; + char mBuffer[MAX_COMMAND_BYTES]; +}; + +static_assert(sizeof(NativeCommandBuffer) < 3 * 4096); + +static int buffersAllocd(0); + +// Get a new NativeCommandBuffer. Can only be called once between freeNativeBuffer calls, +// so that only one buffer exists at a time. +jlong com_android_internal_os_ZygoteCommandBuffer_getNativeBuffer(JNIEnv* env, jclass, jint fd) { + CHECK(buffersAllocd == 0); + ++buffersAllocd; + // MMap explicitly to get it page aligned. + void *bufferMem = mmap(NULL, sizeof(NativeCommandBuffer), PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_POPULATE, -1, 0); + // Currently we mmap and unmap one for every request handled by the Java code. + // That could be improved, but unclear it matters. + if (bufferMem == MAP_FAILED) { + ZygoteFailure(env, nullptr, nullptr, "Failed to map argument buffer"); + } + return (jlong) new(bufferMem) NativeCommandBuffer(fd); +} + +// Delete native command buffer. +void com_android_internal_os_ZygoteCommandBuffer_freeNativeBuffer(JNIEnv* env, jclass, + jlong j_buffer) { + CHECK(buffersAllocd == 1); + NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer); + n_buffer->~NativeCommandBuffer(); + if (munmap(n_buffer, sizeof(NativeCommandBuffer)) != 0) { + ZygoteFailure(env, nullptr, nullptr, "Failed to unmap argument buffer"); + } + --buffersAllocd; +} + +// Clear the buffer, read the line containing the count, and return the count. +jint com_android_internal_os_ZygoteCommandBuffer_nativeGetCount(JNIEnv* env, jclass, + jlong j_buffer) { + NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer); + auto fail_fn = std::bind(ZygoteFailure, env, nullptr, nullptr, _1); + return n_buffer->getCount(fail_fn); +} + +// Explicitly insert a string as the last line (argument) of the buffer. +void com_android_internal_os_ZygoteCommandBuffer_insert(JNIEnv* env, jclass, jlong j_buffer, + jstring line) { + NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer); + size_t lineLen = static_cast<size_t>(env->GetStringUTFLength(line)); + const char* cstring = env->GetStringUTFChars(line, NULL); + n_buffer->insert(cstring, lineLen); + env->ReleaseStringUTFChars(line, cstring); +} + +// Read a line from the buffer, refilling as necessary. +jstring com_android_internal_os_ZygoteCommandBuffer_nativeNextArg(JNIEnv* env, jclass, + jlong j_buffer) { + NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer); + auto fail_fn = std::bind(ZygoteFailure, env, n_buffer->niceNameAddr(), nullptr, _1); + auto line = n_buffer->readLine(fail_fn); + if (!line.has_value()) { + fail_fn("Incomplete zygote command"); + } + auto [cresult, endp] = line.value(); + // OK to temporarily clobber the buffer, since this is not thread safe, and we're modifying + // the buffer anyway. + *endp = '\0'; + jstring result = env->NewStringUTF(cresult); + *endp = '\n'; + return result; +} + +// Read all lines from the current command into the buffer, and then reset the buffer, so +// we will start reading again at the beginning of the command, starting with the argument +// count. And we don't need access to the fd to do so. +void com_android_internal_os_ZygoteCommandBuffer_nativeReadFullyAndReset(JNIEnv* env, jclass, + jlong j_buffer) { + NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer); + auto fail_fn = std::bind(ZygoteFailure, env, n_buffer->niceNameAddr(), nullptr, _1); + n_buffer->readAllLines(fail_fn); + n_buffer->reset(); +} + +// Fork a child as specified by the current command buffer, and refill the command +// buffer from the given socket. So long as the result is another simple fork command, +// repeat this process. +// It must contain a fork command, which is currently restricted not to fork another +// zygote or involve a wrapper process. +// The initial buffer should be partially or entirely read; we read it fully and reset it. +// When we return, the buffer contains the command we couldn't handle, and has been reset(). +// We return false in the parent when we see a command we didn't understand, and thus the +// command in the buffer still needs to be executed. +// We return true in each child. +// We only process fork commands if the peer uid matches expected_uid. +// For every fork command after the first, we check that the requested uid is at +// least minUid. +NO_PAC_FUNC +jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly( + JNIEnv* env, + jclass, + jlong j_buffer, + jint zygote_socket_fd, + jint expected_uid, + jint minUid, + jstring managed_nice_name) { + + NativeCommandBuffer* n_buffer = reinterpret_cast<NativeCommandBuffer*>(j_buffer); + int session_socket = n_buffer->getFd(); + std::vector<int> session_socket_fds {session_socket}; + auto fail_fn_1 = std::bind(ZygoteFailure, env, static_cast<const char*>(nullptr), + static_cast<jstring>(managed_nice_name), _1); + // This binds to the nice name address; the actual names are updated by isSimpleForkCommand: + auto fail_fn_n = std::bind(ZygoteFailure, env, n_buffer->niceNameAddr(), + static_cast<jstring>(nullptr), _1); + auto fail_fn_z = std::bind(ZygoteFailure, env, "zygote", nullptr, _1); + + struct pollfd fd_structs[2]; + static const int ZYGOTE_IDX = 0; + static const int SESSION_IDX = 1; + fd_structs[ZYGOTE_IDX].fd = zygote_socket_fd; + fd_structs[ZYGOTE_IDX].events = POLLIN; + fd_structs[SESSION_IDX].fd = session_socket; + fd_structs[SESSION_IDX].events = POLLIN; + + struct timeval timeout; + socklen_t timeout_size = sizeof timeout; + if (getsockopt(session_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, &timeout_size) != 0) { + fail_fn_z("Failed to retrieve session socket timeout"); + } + + struct ucred credentials; + socklen_t cred_size = sizeof credentials; + if (getsockopt(n_buffer->getFd(), SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1 + || cred_size != sizeof credentials) { + fail_fn_1("ForkMany failed to get initial credentials, %s", strerror(errno)); + } + + bool first_time = true; + do { + if (credentials.uid != expected_uid) { + return JNI_FALSE; + } + n_buffer->readAllLines(first_time ? fail_fn_1 : fail_fn_n); + n_buffer->reset(); + int pid = zygote::forkApp(env, /* no pipe FDs */ -1, -1, session_socket_fds, + /*args_known=*/ true, /*is_priority_fork=*/ true, + /*purge=*/ first_time); + if (pid == 0) { + return JNI_TRUE; + } + // We're in the parent. Write big-endian pid, followed by a boolean. + char pid_buf[5]; + int tmp_pid = pid; + for (int i = 3; i >= 0; --i) { + pid_buf[i] = tmp_pid & 0xff; + tmp_pid >>= 8; + } + pid_buf[4] = 0; // Process is not wrapped. + int res = write(session_socket, pid_buf, 5); + if (res != 5) { + if (res == -1) { + (first_time ? fail_fn_1 : fail_fn_n) + (CREATE_ERROR("Pid write error %d: %s", errno, strerror(errno))); + } else { + (first_time ? fail_fn_1 : fail_fn_n) + (CREATE_ERROR("Write unexpectedly returned short: %d < 5", res)); + } + } + // Clear buffer and get count from next command. + n_buffer->clear(); + for (;;) { + // Poll isn't strictly necessary for now. But without it, disconnect is hard to detect. + int poll_res = TEMP_FAILURE_RETRY(poll(fd_structs, 2, -1 /* infinite timeout */)); + if ((fd_structs[SESSION_IDX].revents & POLLIN) != 0) { + if (n_buffer->getCount(fail_fn_z) != 0) { + break; + } // else disconnected; + } else if (poll_res == 0 || (fd_structs[ZYGOTE_IDX].revents & POLLIN) == 0) { + fail_fn_z( + CREATE_ERROR("Poll returned with no descriptors ready! Poll returned %d", poll_res)); + } + // We've now seen either a disconnect or connect request. + close(session_socket); + int new_fd = accept(zygote_socket_fd, nullptr, nullptr); + if (new_fd == -1) { + fail_fn_z("Accept(%d) failed: %s", zygote_socket_fd, strerror(errno)); + } + if (new_fd != session_socket) { + // Move new_fd back to the old value, so that we don't have to change Java-level data + // structures to reflect a change. This implicitly closes the old one. + if (dup2(new_fd, session_socket) != session_socket) { + fail_fn_z(CREATE_ERROR("Failed to move fd %d to %d: %s", + new_fd, session_socket, strerror(errno))); + } + close(new_fd); + } + // If we ever return, we effectively reuse the old Java ZygoteConnection. + // None of its state needs to change. + if (setsockopt(session_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, timeout_size) != 0) { + fail_fn_z(CREATE_ERROR("Failed to set receive timeout for socket %d: %s", + session_socket, strerror(errno))); + } + if (setsockopt(session_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, timeout_size) != 0) { + fail_fn_z(CREATE_ERROR("Failed to set send timeout for socket %d: %s", + session_socket, strerror(errno))); + } + if (getsockopt(session_socket, SOL_SOCKET, SO_PEERCRED, &credentials, &cred_size) == -1) { + fail_fn_z(CREATE_ERROR("ForkMany failed to get credentials: %s", strerror(errno))); + } + if (cred_size != sizeof credentials) { + fail_fn_z(CREATE_ERROR("ForkMany credential size = %d, should be %d", + cred_size, static_cast<int>(sizeof credentials))); + } + } + first_time = false; + } while (n_buffer->isSimpleForkCommand(minUid, fail_fn_n)); + ALOGW("forkRepeatedly terminated due to non-simple command"); + n_buffer->logState(); + n_buffer->reset(); + return JNI_FALSE; +} + +#define METHOD_NAME(m) com_android_internal_os_ZygoteCommandBuffer_ ## m + +static const JNINativeMethod gMethods[] = { + {"getNativeBuffer", "(I)J", (void *) METHOD_NAME(getNativeBuffer)}, + {"freeNativeBuffer", "(J)V", (void *) METHOD_NAME(freeNativeBuffer)}, + {"insert", "(JLjava/lang/String;)V", (void *) METHOD_NAME(insert)}, + {"nativeNextArg", "(J)Ljava/lang/String;", (void *) METHOD_NAME(nativeNextArg)}, + {"nativeReadFullyAndReset", "(J)V", (void *) METHOD_NAME(nativeReadFullyAndReset)}, + {"nativeGetCount", "(J)I", (void *) METHOD_NAME(nativeGetCount)}, + {"nativeForkRepeatedly", "(JIIILjava/lang/String;)Z", + (void *) METHOD_NAME(nativeForkRepeatedly)}, +}; + +int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv* env) { + return RegisterMethodsOrDie(env, "com/android/internal/os/ZygoteCommandBuffer", gMethods, + NELEM(gMethods)); +} + +} // namespace android diff --git a/core/proto/android/content/package_item_info.proto b/core/proto/android/content/package_item_info.proto index e6833066f17e..bb39ea810add 100644 --- a/core/proto/android/content/package_item_info.proto +++ b/core/proto/android/content/package_item_info.proto @@ -110,6 +110,8 @@ message ApplicationInfoProto { optional int32 network_security_config_res = 17; optional int32 category = 18; optional int32 enable_gwp_asan = 19; + optional int32 enable_memtag = 20; + optional bool native_heap_zero_init = 21; } optional Detail detail = 17; } diff --git a/core/proto/android/service/netstats.proto b/core/proto/android/service/netstats.proto index 8ebb4a9f6649..c8cdfddc3985 100644 --- a/core/proto/android/service/netstats.proto +++ b/core/proto/android/service/netstats.proto @@ -80,6 +80,8 @@ message NetworkIdentityProto { optional bool metered = 5; optional bool default_network = 6; + + optional int32 oem_managed_network = 7; } // Corresponds to NetworkStatsRecorder. diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index d1e6111dc35f..dc935c09ad8f 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1270,11 +1270,13 @@ android:protectionLevel="dangerous|instant" /> <!-- ====================================================================== --> - <!-- Permissions for accessing the UCE Service --> + <!-- Permissions for accessing the vendor UCE Service --> <!-- ====================================================================== --> <!-- @hide Allows an application to Access UCE-Presence. <p>Protection level: signature|privileged + @deprecated Framework should no longer use this permission to access the vendor UCE service + using AIDL, it is instead implemented by RcsCapabilityExchangeImplBase --> <permission android:name="android.permission.ACCESS_UCE_PRESENCE_SERVICE" android:permissionGroup="android.permission-group.PHONE" @@ -1282,6 +1284,8 @@ <!-- @hide Allows an application to Access UCE-OPTIONS. <p>Protection level: signature|privileged + @deprecated Framework should no longer use this permission to access the vendor UCE service + using AIDL, it is instead implemented by RcsCapabilityExchangeImplBase --> <permission android:name="android.permission.ACCESS_UCE_OPTIONS_SERVICE" android:permissionGroup="android.permission-group.PHONE" @@ -2366,6 +2370,13 @@ <permission android:name="android.permission.BIND_GBA_SERVICE" android:protectionLevel="signature" /> + <!-- Required for an Application to access APIs related to RCS User Capability Exchange. + <p>Protection level: signature|privileged + @SystemApi + @hide --> + <permission android:name="android.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE" + android:protectionLevel="signature|privileged" /> + <!-- ================================== --> <!-- Permissions for sdcard interaction --> <!-- ================================== --> diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 0c63c1096a3a..47dbd64c0402 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1560,6 +1560,13 @@ <enum name="always" value="1" /> </attr> + <attr name="memtagMode"> + <enum name="default" value="-1" /> + <enum name="off" value="0" /> + <enum name="async" value="1" /> + <enum name="sync" value="2" /> + </attr> + <!-- The <code>manifest</code> tag is the root of an <code>AndroidManifest.xml</code> file, describing the contents of an Android package (.apk) file. One @@ -1827,6 +1834,10 @@ <attr name="gwpAsanMode" /> + <attr name="memtagMode" /> + + <attr name="nativeHeapZeroInit" format="boolean" /> + <!-- @hide no longer used, kept to preserve padding --> <attr name="allowAutoRevokePermissionsExemption" format="boolean" /> @@ -2350,6 +2361,8 @@ <!-- Required name of the process that is allowed --> <attr name="process" /> <attr name="gwpAsanMode" /> + <attr name="memtagMode" /> + <attr name="nativeHeapZeroInit" /> </declare-styleable> <!-- The <code>deny-permission</code> tag specifies that a permission is to be denied diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index ee45249c2030..93758b6d66d6 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4414,4 +4414,7 @@ <!-- Whether to select voice/data/sms preference without user confirmation --> <bool name="config_voice_data_sms_auto_fallback">false</bool> + + <!-- Whether to allow the caching of the SIM PIN for verification after unattended reboot --> + <bool name="config_allow_pin_storage_for_unattended_reboot">true</bool> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 0874a77815b5..0f846d3dbad9 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3046,6 +3046,8 @@ <public name="canPauseRecording" /> <!-- attribute definitions go here --> <public name="requireDeviceScreenOn" /> + <public name="memtagMode" /> + <public name="nativeHeapZeroInit" /> </public-group> <public-group type="drawable" first-id="0x010800b5"> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 4509b4e0b3f9..fc75463a44fa 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2612,6 +2612,7 @@ <java-symbol type="bool" name="config_defaultWindowFeatureContextMenu" /> <java-symbol type="bool" name="config_overrideRemoteViewsActivityTransition" /> <java-symbol type="attr" name="colorProgressBackgroundNormal" /> + <java-symbol type="bool" name="config_allow_pin_storage_for_unattended_reboot" /> <java-symbol type="layout" name="simple_account_item" /> <java-symbol type="string" name="prohibit_manual_network_selection_in_gobal_mode" /> diff --git a/core/tests/coretests/src/android/view/OWNERS b/core/tests/coretests/src/android/view/OWNERS index 80165f065995..fa1aa5eab26c 100644 --- a/core/tests/coretests/src/android/view/OWNERS +++ b/core/tests/coretests/src/android/view/OWNERS @@ -9,3 +9,6 @@ per-file *Focus* = file:/services/core/java/com/android/server/wm/OWNERS per-file *Insets* = file:/services/core/java/com/android/server/wm/OWNERS per-file *View* = file:/services/core/java/com/android/server/wm/OWNERS per-file *Visibility* = file:/services/core/java/com/android/server/wm/OWNERS + +# Scroll Capture +per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS diff --git a/core/tests/coretests/src/com/android/internal/view/OWNERS b/core/tests/coretests/src/com/android/internal/view/OWNERS new file mode 100644 index 000000000000..1dad10de5ac7 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/view/OWNERS @@ -0,0 +1,3 @@ +# Scroll Capture +per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS +per-file *CaptureHelper*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 5b32641cc811..eb6bf3e03732 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -305,6 +305,7 @@ applications that come with the platform <!-- Needed for test only --> <permission name="android.permission.MODIFY_DAY_NIGHT_MODE"/> <permission name="android.permission.ACCESS_LOWPAN_STATE"/> + <permission name="android.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE"/> <permission name="android.permission.BACKUP"/> <permission name="android.permission.BATTERY_STATS"/> <permission name="android.permission.BIND_APPWIDGET"/> diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml index 4c214b529b39..d2b47c6336c4 100644 --- a/data/fonts/fonts.xml +++ b/data/fonts/fonts.xml @@ -60,7 +60,7 @@ <alias name="sans-serif-condensed-medium" to="sans-serif-condensed" weight="500" /> <family name="serif"> - <font weight="400" style="normal">NotoSerif-Regular.ttf</font> + <font weight="400" style="normal">NotoSerif.ttf</font> <font weight="700" style="normal">NotoSerif-Bold.ttf</font> <font weight="400" style="italic">NotoSerif-Italic.ttf</font> <font weight="700" style="italic">NotoSerif-BoldItalic.ttf</font> @@ -112,33 +112,33 @@ <!-- fallback fonts --> <family lang="und-Arab" variant="elegant"> - <font weight="400" style="normal">NotoNaskhArabic-Regular.ttf</font> + <font weight="400" style="normal">NotoNaskhArabic.ttf</font> <font weight="700" style="normal">NotoNaskhArabic-Bold.ttf</font> </family> <family lang="und-Arab" variant="compact"> - <font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font> + <font weight="400" style="normal">NotoNaskhArabicUI.ttf</font> <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font> </family> <family lang="und-Ethi"> - <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font> + <font weight="400" style="normal">NotoSansEthiopic.ttf</font> <font weight="700" style="normal">NotoSansEthiopic-Bold.ttf</font> <font weight="400" style="normal" fallbackFor="serif">NotoSerifEthiopic-Regular.otf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifEthiopic-Bold.otf</font> </family> <family lang="und-Hebr"> - <font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font> + <font weight="400" style="normal">NotoSansHebrew.ttf</font> <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font> <font weight="400" style="normal" fallbackFor="serif">NotoSerifHebrew-Regular.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifHebrew-Bold.ttf</font> </family> <family lang="und-Thai" variant="elegant"> - <font weight="400" style="normal">NotoSansThai-Regular.ttf</font> + <font weight="400" style="normal">NotoSansThai.ttf</font> <font weight="700" style="normal">NotoSansThai-Bold.ttf</font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifThai-Regular.ttf</font> + <font weight="400" style="normal" fallbackFor="serif">NotoSerifThai.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifThai-Bold.ttf</font> </family> <family lang="und-Thai" variant="compact"> - <font weight="400" style="normal">NotoSansThaiUI-Regular.ttf</font> + <font weight="400" style="normal">NotoSansThaiUI.ttf</font> <font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font> </family> <family lang="und-Armn"> @@ -149,28 +149,28 @@ <font weight="700" style="normal" fallbackFor="serif">NotoSerifArmenian-Bold.otf</font> </family> <family lang="und-Geor,und-Geok"> - <font weight="400" style="normal">NotoSansGeorgian-VF.ttf + <font weight="400" style="normal">NotoSansGeorgian-Regular.ttf <axis tag="wght" stylevalue="400" /> </font> - <font weight="500" style="normal">NotoSansGeorgian-VF.ttf + <font weight="500" style="normal">NotoSansGeorgian-Regular.ttf <axis tag="wght" stylevalue="500" /> </font> - <font weight="600" style="normal">NotoSansGeorgian-VF.ttf + <font weight="600" style="normal">NotoSansGeorgian-Regular.ttf <axis tag="wght" stylevalue="600" /> </font> - <font weight="700" style="normal">NotoSansGeorgian-VF.ttf + <font weight="700" style="normal">NotoSansGeorgian-Regular.ttf <axis tag="wght" stylevalue="700" /> </font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf + <font weight="400" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf <axis tag="wght" stylevalue="400" /> </font> - <font weight="500" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf + <font weight="500" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf <axis tag="wght" stylevalue="500" /> </font> - <font weight="600" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf + <font weight="600" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf <axis tag="wght" stylevalue="600" /> </font> - <font weight="700" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf + <font weight="700" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf <axis tag="wght" stylevalue="700" /> </font> </family> @@ -178,7 +178,7 @@ <font weight="400" style="normal">NotoSansDevanagari-Regular.otf</font> <font weight="500" style="normal">NotoSansDevanagari-Medium.otf</font> <font weight="700" style="normal">NotoSansDevanagari-Bold.otf</font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifDevanagari-Regular.ttf</font> + <font weight="400" style="normal" fallbackFor="serif">NotoSerifDevanagari.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifDevanagari-Bold.ttf</font> </family> <family lang="und-Deva" variant="compact"> @@ -191,23 +191,23 @@ danda characters. --> <family lang="und-Gujr" variant="elegant"> - <font weight="400" style="normal">NotoSansGujarati-Regular.ttf</font> + <font weight="400" style="normal">NotoSansGujarati.ttf</font> <font weight="700" style="normal">NotoSansGujarati-Bold.ttf</font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifGujarati-Regular.ttf</font> + <font weight="400" style="normal" fallbackFor="serif">NotoSerifGujarati.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifGujarati-Bold.ttf</font> </family> <family lang="und-Gujr" variant="compact"> - <font weight="400" style="normal">NotoSansGujaratiUI-Regular.ttf</font> + <font weight="400" style="normal">NotoSansGujaratiUI.ttf</font> <font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font> </family> <family lang="und-Guru" variant="elegant"> - <font weight="400" style="normal">NotoSansGurmukhi-Regular.ttf</font> + <font weight="400" style="normal">NotoSansGurmukhi.ttf</font> <font weight="700" style="normal">NotoSansGurmukhi-Bold.ttf</font> <font weight="400" style="normal" fallbackFor="serif">NotoSerifGurmukhi-Regular.otf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifGurmukhi-Bold.otf</font> </family> <family lang="und-Guru" variant="compact"> - <font weight="400" style="normal">NotoSansGurmukhiUI-Regular.ttf</font> + <font weight="400" style="normal">NotoSansGurmukhiUI.ttf</font> <font weight="700" style="normal">NotoSansGurmukhiUI-Bold.ttf</font> </family> <family lang="und-Taml" variant="elegant"> @@ -226,7 +226,7 @@ <font weight="400" style="normal">NotoSansMalayalam-Regular.otf</font> <font weight="500" style="normal">NotoSansMalayalam-Medium.otf</font> <font weight="700" style="normal">NotoSansMalayalam-Bold.otf</font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifMalayalam-Regular.ttf</font> + <font weight="400" style="normal" fallbackFor="serif">NotoSerifMalayalam.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifMalayalam-Bold.ttf</font> </family> <family lang="und-Mlym" variant="compact"> @@ -238,7 +238,7 @@ <font weight="400" style="normal">NotoSansBengali-Regular.otf</font> <font weight="500" style="normal">NotoSansBengali-Medium.otf</font> <font weight="700" style="normal">NotoSansBengali-Bold.otf</font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifBengali-Regular.ttf</font> + <font weight="400" style="normal" fallbackFor="serif">NotoSerifBengali.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifBengali-Bold.ttf</font> </family> <family lang="und-Beng" variant="compact"> @@ -247,31 +247,31 @@ <font weight="700" style="normal">NotoSansBengaliUI-Bold.otf</font> </family> <family lang="und-Telu" variant="elegant"> - <font weight="400" style="normal">NotoSansTelugu-Regular.ttf</font> + <font weight="400" style="normal">NotoSansTelugu.ttf</font> <font weight="700" style="normal">NotoSansTelugu-Bold.ttf</font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifTelugu-Regular.ttf</font> + <font weight="400" style="normal" fallbackFor="serif">NotoSerifTelugu.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifTelugu-Bold.ttf</font> </family> <family lang="und-Telu" variant="compact"> - <font weight="400" style="normal">NotoSansTeluguUI-Regular.ttf</font> + <font weight="400" style="normal">NotoSansTeluguUI.ttf</font> <font weight="700" style="normal">NotoSansTeluguUI-Bold.ttf</font> </family> <family lang="und-Knda" variant="elegant"> - <font weight="400" style="normal">NotoSansKannada-Regular.ttf</font> + <font weight="400" style="normal">NotoSansKannada.ttf</font> <font weight="700" style="normal">NotoSansKannada-Bold.ttf</font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifKannada-Regular.ttf</font> + <font weight="400" style="normal" fallbackFor="serif">NotoSerifKannada.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifKannada-Bold.ttf</font> </family> <family lang="und-Knda" variant="compact"> - <font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf</font> + <font weight="400" style="normal">NotoSansKannadaUI.ttf</font> <font weight="700" style="normal">NotoSansKannadaUI-Bold.ttf</font> </family> <family lang="und-Orya" variant="elegant"> - <font weight="400" style="normal">NotoSansOriya-Regular.ttf</font> + <font weight="400" style="normal">NotoSansOriya.ttf</font> <font weight="700" style="normal">NotoSansOriya-Bold.ttf</font> </family> <family lang="und-Orya" variant="compact"> - <font weight="400" style="normal">NotoSansOriyaUI-Regular.ttf</font> + <font weight="400" style="normal">NotoSansOriyaUI.ttf</font> <font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font> </family> @@ -288,39 +288,39 @@ <font weight="700" style="normal">NotoSansSinhalaUI-Bold.otf</font> </family> <family lang="und-Khmr" variant="elegant"> - <font weight="100" style="normal">NotoSansKhmer-VF.ttf + <font weight="100" style="normal">NotoSansKhmer-Regular.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="26.0" /> </font> - <font weight="200" style="normal">NotoSansKhmer-VF.ttf + <font weight="200" style="normal">NotoSansKhmer-Regular.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="39.0" /> </font> - <font weight="300" style="normal">NotoSansKhmer-VF.ttf + <font weight="300" style="normal">NotoSansKhmer-Regular.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="58.0" /> </font> - <font weight="400" style="normal">NotoSansKhmer-VF.ttf + <font weight="400" style="normal">NotoSansKhmer-Regular.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="90.0" /> </font> - <font weight="500" style="normal">NotoSansKhmer-VF.ttf + <font weight="500" style="normal">NotoSansKhmer-Regular.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="108.0" /> </font> - <font weight="600" style="normal">NotoSansKhmer-VF.ttf + <font weight="600" style="normal">NotoSansKhmer-Regular.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="128.0" /> </font> - <font weight="700" style="normal">NotoSansKhmer-VF.ttf + <font weight="700" style="normal">NotoSansKhmer-Regular.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="151.0" /> </font> - <font weight="800" style="normal">NotoSansKhmer-VF.ttf + <font weight="800" style="normal">NotoSansKhmer-Regular.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="169.0" /> </font> - <font weight="900" style="normal">NotoSansKhmer-VF.ttf + <font weight="900" style="normal">NotoSansKhmer-Regular.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="190.0" /> </font> @@ -328,17 +328,17 @@ <font weight="700" style="normal" fallbackFor="serif">NotoSerifKhmer-Bold.otf</font> </family> <family lang="und-Khmr" variant="compact"> - <font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font> + <font weight="400" style="normal">NotoSansKhmerUI.ttf</font> <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font> </family> <family lang="und-Laoo" variant="elegant"> - <font weight="400" style="normal">NotoSansLao-Regular.ttf</font> + <font weight="400" style="normal">NotoSansLao.ttf</font> <font weight="700" style="normal">NotoSansLao-Bold.ttf</font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifLao-Regular.ttf</font> + <font weight="400" style="normal" fallbackFor="serif">NotoSerifLao.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifLao-Bold.ttf</font> </family> <family lang="und-Laoo" variant="compact"> - <font weight="400" style="normal">NotoSansLaoUI-Regular.ttf</font> + <font weight="400" style="normal">NotoSansLaoUI.ttf</font> <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font> </family> <family lang="und-Mymr" variant="elegant"> @@ -354,56 +354,56 @@ <font weight="700" style="normal">NotoSansMyanmarUI-Bold.otf</font> </family> <family lang="und-Thaa"> - <font weight="400" style="normal">NotoSansThaana-Regular.ttf</font> + <font weight="400" style="normal">NotoSansThaana.ttf</font> <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font> </family> <family lang="und-Cham"> - <font weight="400" style="normal">NotoSansCham-Regular.ttf</font> + <font weight="400" style="normal">NotoSansCham.ttf</font> <font weight="700" style="normal">NotoSansCham-Bold.ttf</font> </family> <family lang="und-Ahom"> <font weight="400" style="normal">NotoSansAhom-Regular.otf</font> </family> <family lang="und-Adlm"> - <font weight="400" style="normal">NotoSansAdlam-VF.ttf + <font weight="400" style="normal">NotoSansAdlam-Regular.ttf <axis tag="wght" stylevalue="400" /> </font> - <font weight="500" style="normal">NotoSansAdlam-VF.ttf + <font weight="500" style="normal">NotoSansAdlam-Regular.ttf <axis tag="wght" stylevalue="500" /> </font> - <font weight="600" style="normal">NotoSansAdlam-VF.ttf + <font weight="600" style="normal">NotoSansAdlam-Regular.ttf <axis tag="wght" stylevalue="600" /> </font> - <font weight="700" style="normal">NotoSansAdlam-VF.ttf + <font weight="700" style="normal">NotoSansAdlam-Regular.ttf <axis tag="wght" stylevalue="700" /> </font> </family> <family lang="und-Avst"> - <font weight="400" style="normal">NotoSansAvestan-Regular.ttf</font> + <font weight="400" style="normal">NotoSansAvestan.ttf</font> </family> <family lang="und-Bali"> - <font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font> + <font weight="400" style="normal">NotoSansBalinese.ttf</font> </family> <family lang="und-Bamu"> - <font weight="400" style="normal">NotoSansBamum-Regular.ttf</font> + <font weight="400" style="normal">NotoSansBamum.ttf</font> </family> <family lang="und-Batk"> - <font weight="400" style="normal">NotoSansBatak-Regular.ttf</font> + <font weight="400" style="normal">NotoSansBatak.ttf</font> </family> <family lang="und-Brah"> - <font weight="400" style="normal">NotoSansBrahmi-Regular.ttf</font> + <font weight="400" style="normal">NotoSansBrahmi.ttf</font> </family> <family lang="und-Bugi"> - <font weight="400" style="normal">NotoSansBuginese-Regular.ttf</font> + <font weight="400" style="normal">NotoSansBuginese.ttf</font> </family> <family lang="und-Buhd"> - <font weight="400" style="normal">NotoSansBuhid-Regular.ttf</font> + <font weight="400" style="normal">NotoSansBuhid.ttf</font> </family> <family lang="und-Cans"> - <font weight="400" style="normal">NotoSansCanadianAboriginal-Regular.ttf</font> + <font weight="400" style="normal">NotoSansCanadianAboriginal.ttf</font> </family> <family lang="und-Cari"> - <font weight="400" style="normal">NotoSansCarian-Regular.ttf</font> + <font weight="400" style="normal">NotoSansCarian.ttf</font> </family> <family lang="und-Cakm"> <font weight="400" style="normal">NotoSansChakma-Regular.otf</font> @@ -412,184 +412,184 @@ <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font> </family> <family lang="und-Copt"> - <font weight="400" style="normal">NotoSansCoptic-Regular.ttf</font> + <font weight="400" style="normal">NotoSansCoptic.ttf</font> </family> <family lang="und-Xsux"> - <font weight="400" style="normal">NotoSansCuneiform-Regular.ttf</font> + <font weight="400" style="normal">NotoSansCuneiform.ttf</font> </family> <family lang="und-Cprt"> - <font weight="400" style="normal">NotoSansCypriot-Regular.ttf</font> + <font weight="400" style="normal">NotoSansCypriot.ttf</font> </family> <family lang="und-Dsrt"> - <font weight="400" style="normal">NotoSansDeseret-Regular.ttf</font> + <font weight="400" style="normal">NotoSansDeseret.ttf</font> </family> <family lang="und-Egyp"> - <font weight="400" style="normal">NotoSansEgyptianHieroglyphs-Regular.ttf</font> + <font weight="400" style="normal">NotoSansEgyptianHieroglyphs.ttf</font> </family> <family lang="und-Elba"> <font weight="400" style="normal">NotoSansElbasan-Regular.otf</font> </family> <family lang="und-Glag"> - <font weight="400" style="normal">NotoSansGlagolitic-Regular.ttf</font> + <font weight="400" style="normal">NotoSansGlagolitic.ttf</font> </family> <family lang="und-Goth"> - <font weight="400" style="normal">NotoSansGothic-Regular.ttf</font> + <font weight="400" style="normal">NotoSansGothic.ttf</font> </family> <family lang="und-Hano"> - <font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font> + <font weight="400" style="normal">NotoSansHanunoo.ttf</font> </family> <family lang="und-Armi"> - <font weight="400" style="normal">NotoSansImperialAramaic-Regular.ttf</font> + <font weight="400" style="normal">NotoSansImperialAramaic.ttf</font> </family> <family lang="und-Phli"> - <font weight="400" style="normal">NotoSansInscriptionalPahlavi-Regular.ttf</font> + <font weight="400" style="normal">NotoSansInscriptionalPahlavi.ttf</font> </family> <family lang="und-Prti"> - <font weight="400" style="normal">NotoSansInscriptionalParthian-Regular.ttf</font> + <font weight="400" style="normal">NotoSansInscriptionalParthian.ttf</font> </family> <family lang="und-Java"> <font weight="400" style="normal">NotoSansJavanese-Regular.ttf</font> </family> <family lang="und-Kthi"> - <font weight="400" style="normal">NotoSansKaithi-Regular.ttf</font> + <font weight="400" style="normal">NotoSansKaithi.ttf</font> </family> <family lang="und-Kali"> - <font weight="400" style="normal">NotoSansKayahLi-Regular.ttf</font> + <font weight="400" style="normal">NotoSansKayahLi.ttf</font> </family> <family lang="und-Khar"> - <font weight="400" style="normal">NotoSansKharoshthi-Regular.ttf</font> + <font weight="400" style="normal">NotoSansKharoshthi.ttf</font> </family> <family lang="und-Lepc"> - <font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font> + <font weight="400" style="normal">NotoSansLepcha.ttf</font> </family> <family lang="und-Limb"> - <font weight="400" style="normal">NotoSansLimbu-Regular.ttf</font> + <font weight="400" style="normal">NotoSansLimbu.ttf</font> </family> <family lang="und-Linb"> - <font weight="400" style="normal">NotoSansLinearB-Regular.ttf</font> + <font weight="400" style="normal">NotoSansLinearB.ttf</font> </family> <family lang="und-Lisu"> - <font weight="400" style="normal">NotoSansLisu-Regular.ttf</font> + <font weight="400" style="normal">NotoSansLisu.ttf</font> </family> <family lang="und-Lyci"> - <font weight="400" style="normal">NotoSansLycian-Regular.ttf</font> + <font weight="400" style="normal">NotoSansLycian.ttf</font> </family> <family lang="und-Lydi"> - <font weight="400" style="normal">NotoSansLydian-Regular.ttf</font> + <font weight="400" style="normal">NotoSansLydian.ttf</font> </family> <family lang="und-Mand"> - <font weight="400" style="normal">NotoSansMandaic-Regular.ttf</font> + <font weight="400" style="normal">NotoSansMandaic.ttf</font> </family> <family lang="und-Mtei"> - <font weight="400" style="normal">NotoSansMeeteiMayek-Regular.ttf</font> + <font weight="400" style="normal">NotoSansMeeteiMayek.ttf</font> </family> <family lang="und-Talu"> - <font weight="400" style="normal">NotoSansNewTaiLue-Regular.ttf</font> + <font weight="400" style="normal">NotoSansNewTaiLue.ttf</font> </family> <family lang="und-Nkoo"> - <font weight="400" style="normal">NotoSansNKo-Regular.ttf</font> + <font weight="400" style="normal">NotoSansNKo.ttf</font> </family> <family lang="und-Ogam"> - <font weight="400" style="normal">NotoSansOgham-Regular.ttf</font> + <font weight="400" style="normal">NotoSansOgham.ttf</font> </family> <family lang="und-Olck"> - <font weight="400" style="normal">NotoSansOlChiki-Regular.ttf</font> + <font weight="400" style="normal">NotoSansOlChiki.ttf</font> </family> <family lang="und-Ital"> - <font weight="400" style="normal">NotoSansOldItalic-Regular.ttf</font> + <font weight="400" style="normal">NotoSansOldItalic.ttf</font> </family> <family lang="und-Xpeo"> - <font weight="400" style="normal">NotoSansOldPersian-Regular.ttf</font> + <font weight="400" style="normal">NotoSansOldPersian.ttf</font> </family> <family lang="und-Sarb"> - <font weight="400" style="normal">NotoSansOldSouthArabian-Regular.ttf</font> + <font weight="400" style="normal">NotoSansOldSouthArabian.ttf</font> </family> <family lang="und-Orkh"> - <font weight="400" style="normal">NotoSansOldTurkic-Regular.ttf</font> + <font weight="400" style="normal">NotoSansOldTurkic.ttf</font> </family> <family lang="und-Osge"> <font weight="400" style="normal">NotoSansOsage-Regular.ttf</font> </family> <family lang="und-Osma"> - <font weight="400" style="normal">NotoSansOsmanya-Regular.ttf</font> + <font weight="400" style="normal">NotoSansOsmanya.ttf</font> </family> <family lang="und-Phnx"> - <font weight="400" style="normal">NotoSansPhoenician-Regular.ttf</font> + <font weight="400" style="normal">NotoSansPhoenician.ttf</font> </family> <family lang="und-Rjng"> - <font weight="400" style="normal">NotoSansRejang-Regular.ttf</font> + <font weight="400" style="normal">NotoSansRejang.ttf</font> </family> <family lang="und-Runr"> - <font weight="400" style="normal">NotoSansRunic-Regular.ttf</font> + <font weight="400" style="normal">NotoSansRunic.ttf</font> </family> <family lang="und-Samr"> - <font weight="400" style="normal">NotoSansSamaritan-Regular.ttf</font> + <font weight="400" style="normal">NotoSansSamaritan.ttf</font> </family> <family lang="und-Saur"> - <font weight="400" style="normal">NotoSansSaurashtra-Regular.ttf</font> + <font weight="400" style="normal">NotoSansSaurashtra.ttf</font> </family> <family lang="und-Shaw"> - <font weight="400" style="normal">NotoSansShavian-Regular.ttf</font> + <font weight="400" style="normal">NotoSansShavian.ttf</font> </family> <family lang="und-Sund"> - <font weight="400" style="normal">NotoSansSundanese-Regular.ttf</font> + <font weight="400" style="normal">NotoSansSundanese.ttf</font> </family> <family lang="und-Sylo"> - <font weight="400" style="normal">NotoSansSylotiNagri-Regular.ttf</font> + <font weight="400" style="normal">NotoSansSylotiNagri.ttf</font> </family> <!-- Esrangela should precede Eastern and Western Syriac, since it's our default form. --> <family lang="und-Syre"> - <font weight="400" style="normal">NotoSansSyriacEstrangela-Regular.ttf</font> + <font weight="400" style="normal">NotoSansSyriacEstrangela.ttf</font> </family> <family lang="und-Syrn"> - <font weight="400" style="normal">NotoSansSyriacEastern-Regular.ttf</font> + <font weight="400" style="normal">NotoSansSyriacEastern.ttf</font> </family> <family lang="und-Syrj"> - <font weight="400" style="normal">NotoSansSyriacWestern-Regular.ttf</font> + <font weight="400" style="normal">NotoSansSyriacWestern.ttf</font> </family> <family lang="und-Tglg"> - <font weight="400" style="normal">NotoSansTagalog-Regular.ttf</font> + <font weight="400" style="normal">NotoSansTagalog.ttf</font> </family> <family lang="und-Tagb"> - <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font> + <font weight="400" style="normal">NotoSansTagbanwa.ttf</font> </family> <family lang="und-Lana"> - <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font> + <font weight="400" style="normal">NotoSansTaiTham.ttf</font> </family> <family lang="und-Tavt"> - <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font> + <font weight="400" style="normal">NotoSansTaiViet.ttf</font> </family> <family lang="und-Tibt"> - <font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font> + <font weight="400" style="normal">NotoSansTibetan.ttf</font> <font weight="700" style="normal">NotoSansTibetan-Bold.ttf</font> </family> <family lang="und-Tfng"> <font weight="400" style="normal">NotoSansTifinagh-Regular.otf</font> </family> <family lang="und-Ugar"> - <font weight="400" style="normal">NotoSansUgaritic-Regular.ttf</font> + <font weight="400" style="normal">NotoSansUgaritic.ttf</font> </family> <family lang="und-Vaii"> - <font weight="400" style="normal">NotoSansVai-Regular.ttf</font> + <font weight="400" style="normal">NotoSansVai.ttf</font> </family> <family> <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font> </family> <family lang="zh-Hans"> - <font weight="400" style="normal" index="2">NotoSansCJK-Regular.ttc</font> - <font weight="400" style="normal" index="2" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font> + <font weight="400" style="normal" index="2">NotoSansCJKjp-Regular.otc</font> + <font weight="400" style="normal" index="2" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font> </family> <family lang="zh-Hant,zh-Bopo"> - <font weight="400" style="normal" index="3">NotoSansCJK-Regular.ttc</font> - <font weight="400" style="normal" index="3" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font> + <font weight="400" style="normal" index="3">NotoSansCJKjp-Regular.otc</font> + <font weight="400" style="normal" index="3" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font> </family> <family lang="ja"> - <font weight="400" style="normal" index="0">NotoSansCJK-Regular.ttc</font> - <font weight="400" style="normal" index="0" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font> + <font weight="400" style="normal" index="0">NotoSansCJKjp-Regular.otc</font> + <font weight="400" style="normal" index="0" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font> </family> <family lang="ko"> - <font weight="400" style="normal" index="1">NotoSansCJK-Regular.ttc</font> - <font weight="400" style="normal" index="1" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font> + <font weight="400" style="normal" index="1">NotoSansCJKjp-Regular.otc</font> + <font weight="400" style="normal" index="1" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font> </family> <family lang="und-Zsye"> <font weight="400" style="normal">NotoColorEmoji.ttf</font> @@ -602,16 +602,16 @@ override the East Asian punctuation for Chinese. --> <family lang="und-Tale"> - <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font> + <font weight="400" style="normal">NotoSansTaiLe.ttf</font> </family> <family lang="und-Yiii"> - <font weight="400" style="normal">NotoSansYi-Regular.ttf</font> + <font weight="400" style="normal">NotoSansYi.ttf</font> </family> <family lang="und-Mong"> - <font weight="400" style="normal">NotoSansMongolian-Regular.ttf</font> + <font weight="400" style="normal">NotoSansMongolian.ttf</font> </family> <family lang="und-Phag"> - <font weight="400" style="normal">NotoSansPhagsPa-Regular.ttf</font> + <font weight="400" style="normal">NotoSansPhagsPa.ttf</font> </family> <family lang="und-Hluw"> <font weight="400" style="normal">NotoSansAnatolianHieroglyphs-Regular.otf</font> diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java index c81c8c54d88a..ed789f03f9ba 100644 --- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java +++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.security.usermanager.IKeystoreUserManager; +import android.system.keystore2.Domain; import android.system.keystore2.ResponseCode; import android.util.Log; @@ -39,7 +40,7 @@ public class AndroidKeyStoreMaintenance { } /** - * Informs keystore2 about adding a user + * Informs Keystore 2.0 about adding a user * * @param userId - Android user id of the user being added * @return 0 if successful or a {@code ResponseCode} @@ -60,7 +61,7 @@ public class AndroidKeyStoreMaintenance { } /** - * Informs keystore2 about removing a usergit mer + * Informs Keystore 2.0 about removing a usergit mer * * @param userId - Android user id of the user being removed * @return 0 if successful or a {@code ResponseCode} @@ -81,7 +82,7 @@ public class AndroidKeyStoreMaintenance { } /** - * Informs keystore2 about changing user's password + * Informs Keystore 2.0 about changing user's password * * @param userId - Android user id of the user * @param password - a secret derived from the synthetic password provided by the @@ -102,4 +103,22 @@ public class AndroidKeyStoreMaintenance { return SYSTEM_ERROR; } } + + /** + * Informs Keystore 2.0 that an app was uninstalled and the corresponding namspace is to + * be cleared. + */ + public static int clearNamespace(@Domain int domain, long namespace) { + if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0; + try { + getService().clearNamespace(domain, namespace); + return 0; + } catch (ServiceSpecificException e) { + Log.e(TAG, "clearNamespace failed", e); + return e.errorCode; + } catch (Exception e) { + Log.e(TAG, "Can not connect to keystore", e); + return SYSTEM_ERROR; + } + } } diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl index f708298a2cbd..d00f5f669594 100644 --- a/keystore/java/android/security/IKeyChainService.aidl +++ b/keystore/java/android/security/IKeyChainService.aidl @@ -37,8 +37,6 @@ interface IKeyChainService { void setUserSelectable(String alias, boolean isUserSelectable); int generateKeyPair(in String algorithm, in ParcelableKeyGenParameterSpec spec); - int attestKey(in String alias, in byte[] challenge, in int[] idAttestationFlags, - out KeymasterCertificateChain chain); boolean setKeyPairCertificate(String alias, in byte[] userCert, in byte[] certChain); // APIs used by CertInstaller and DevicePolicyManager diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java index 63690d3c1567..d59ca98433a9 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -40,6 +40,8 @@ import android.os.UserManager; import android.security.keystore.AndroidKeyStoreProvider; import android.security.keystore.KeyPermanentlyInvalidatedException; import android.security.keystore.KeyProperties; +import android.system.keystore2.Domain; +import android.system.keystore2.KeyDescriptor; import com.android.org.conscrypt.TrustedCertificateStore; @@ -622,6 +624,33 @@ public final class KeyChain { return null; } + /** + * This prefix is used to disambiguate grant aliase strings from normal key alias strings. + * Technically, a key alias string can use the same prefix. However, a collision does not + * lead to privilege escalation, because grants are access controlled in the Keystore daemon. + * @hide + */ + public static final String GRANT_ALIAS_PREFIX = "ks2_keychain_grant_id:"; + + private static KeyDescriptor getGrantDescriptor(String keyid) { + KeyDescriptor result = new KeyDescriptor(); + result.domain = Domain.GRANT; + result.blob = null; + result.alias = null; + try { + result.nspace = Long.parseUnsignedLong( + keyid.substring(GRANT_ALIAS_PREFIX.length()), 16 /* radix */); + } catch (NumberFormatException e) { + return null; + } + return result; + } + + /** @hide */ + public static String getGrantString(KeyDescriptor key) { + return String.format(GRANT_ALIAS_PREFIX + "%016X", key.nspace); + } + /** @hide */ @Nullable @WorkerThread public static KeyPair getKeyPair(@NonNull Context context, @NonNull String alias) @@ -645,11 +674,23 @@ public final class KeyChain { if (keyId == null) { return null; + } + + if (AndroidKeyStoreProvider.isKeystore2Enabled()) { + try { + return android.security.keystore2.AndroidKeyStoreProvider + .loadAndroidKeyStoreKeyPairFromKeystore( + KeyStore2.getInstance(), + getGrantDescriptor(keyId)); + } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) { + throw new KeyChainException(e); + } } else { try { return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore( KeyStore.getInstance(), keyId, KeyStore.UID_SELF); - } catch (RuntimeException | UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) { + } catch (RuntimeException | UnrecoverableKeyException + | KeyPermanentlyInvalidatedException e) { throw new KeyChainException(e); } } @@ -767,11 +808,8 @@ public final class KeyChain { @Deprecated public static boolean isBoundKeyAlgorithm( @NonNull @KeyProperties.KeyAlgorithmEnum String algorithm) { - if (!isKeyAlgorithmSupported(algorithm)) { - return false; - } - - return KeyStore.getInstance().isHardwareBacked(algorithm); + // All supported algorithms are hardware backed. Individual keys may not be. + return true; } /** @hide */ diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 198df40c7d7b..93658e69eac8 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -43,6 +43,7 @@ import android.security.keystore.KeyPermanentlyInvalidatedException; import android.security.keystore.KeyProperties; import android.security.keystore.KeystoreResponse; import android.security.keystore.UserNotAuthenticatedException; +import android.system.keystore2.Domain; import android.util.Log; import com.android.internal.org.bouncycastle.asn1.ASN1InputStream; @@ -466,6 +467,9 @@ public class KeyStore { public boolean clearUid(int uid) { try { + if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) { + return AndroidKeyStoreMaintenance.clearNamespace(Domain.APP, uid) == 0; + } return mBinder.clear_uid(uid) == NO_ERROR; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java index 476e4d7b7b18..6ac3821d0f9c 100644 --- a/keystore/java/android/security/KeyStore2.java +++ b/keystore/java/android/security/KeyStore2.java @@ -24,6 +24,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.security.keymaster.KeymasterDefs; +import android.system.keystore2.Domain; import android.system.keystore2.IKeystoreService; import android.system.keystore2.KeyDescriptor; import android.system.keystore2.KeyEntryResponse; @@ -157,6 +158,50 @@ public class KeyStore2 { } /** + * Grant string prefix as used by the keystore boringssl engine. Must be kept in sync + * with system/security/keystore-engine. Note: The prefix here includes the 0x which + * std::stringstream used in keystore-engine needs to identify the number as hex represented. + * Here we include it in the prefix, because Long#parseUnsignedLong does not understand it + * and gets the radix as explicit argument. + * @hide + */ + private static final String KEYSTORE_ENGINE_GRANT_ALIAS_PREFIX = + "ks2_keystore-engine_grant_id:0x"; + + /** + * This function turns a grant identifier into a specific string that is understood by the + * keystore-engine in system/security/keystore-engine. Is only used by VPN and WI-FI components + * to allow certain system components like racoon or vendor components like WPA supplicant + * to use keystore keys with boring ssl. + * + * @param grantId the grant id as returned by {@link #grant} in the {@code nspace} filed of + * the resulting {@code KeyDescriptor}. + * @return The grant descriptor string. + * @hide + */ + public static String makeKeystoreEngineGrantString(long grantId) { + return String.format("%s%016X", KEYSTORE_ENGINE_GRANT_ALIAS_PREFIX, grantId); + } + + /** + * Convenience function to turn a keystore engine grant string as returned by + * {@link #makeKeystoreEngineGrantString(long)} back into a grant KeyDescriptor. + * + * @param grantString As string returned by {@link #makeKeystoreEngineGrantString(long)} + * @return The grant key descriptor. + * @hide + */ + public static KeyDescriptor keystoreEngineGrantString2KeyDescriptor(String grantString) { + KeyDescriptor key = new KeyDescriptor(); + key.domain = Domain.GRANT; + key.nspace = Long.parseUnsignedLong( + grantString.substring(KEYSTORE_ENGINE_GRANT_ALIAS_PREFIX.length()), 16); + key.alias = null; + key.blob = null; + return key; + } + + /** * Create a grant that allows the grantee identified by {@code granteeUid} to use * the key specified by {@code descriptor} withint the restrictions given by * {@code accessVectore}. diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java index e1011155248e..d36695b9b410 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java @@ -43,6 +43,7 @@ import java.security.interfaces.RSAPublicKey; import javax.crypto.Cipher; import javax.crypto.Mac; +import javax.crypto.SecretKey; /** * A provider focused on providing JCA interfaces for the Android KeyStore. @@ -273,10 +274,10 @@ public class AndroidKeyStoreProvider extends Provider { /** @hide **/ @NonNull public static KeyPair loadAndroidKeyStoreKeyPairFromKeystore( - @NonNull KeyStore2 keyStore, @NonNull String privateKeyAlias, int namespace) + @NonNull KeyStore2 keyStore, @NonNull KeyDescriptor descriptor) throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { AndroidKeyStoreKey key = - loadAndroidKeyStoreKeyFromKeystore(keyStore, privateKeyAlias, namespace); + loadAndroidKeyStoreKeyFromKeystore(keyStore, descriptor); if (key instanceof AndroidKeyStorePublicKey) { AndroidKeyStorePublicKey publicKey = (AndroidKeyStorePublicKey) key; return new KeyPair(publicKey, publicKey.getPrivateKey()); @@ -299,13 +300,26 @@ public class AndroidKeyStoreProvider extends Provider { } } + /** @hide **/ + @NonNull + public static SecretKey loadAndroidKeyStoreSecretKeyFromKeystore( + @NonNull KeyStore2 keyStore, @NonNull KeyDescriptor descriptor) + throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { + + AndroidKeyStoreKey key = + loadAndroidKeyStoreKeyFromKeystore(keyStore, descriptor); + if (key instanceof SecretKey) { + return (SecretKey) key; + } else { + throw new UnrecoverableKeyException("No secret key found by the given alias."); + } + } @NonNull private static AndroidKeyStoreSecretKey makeAndroidKeyStoreSecretKeyFromKeyEntryResponse( @NonNull KeyDescriptor descriptor, @NonNull KeyEntryResponse response, int algorithm, int digest) throws UnrecoverableKeyException { - @KeyProperties.KeyAlgorithmEnum String keyAlgorithmString; try { keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm( @@ -336,8 +350,7 @@ public class AndroidKeyStoreProvider extends Provider { @NonNull public static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore( @NonNull KeyStore2 keyStore, @NonNull String alias, int namespace) - throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { - + throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { KeyDescriptor descriptor = new KeyDescriptor(); if (namespace == KeyProperties.NAMESPACE_APPLICATION) { descriptor.nspace = KeyProperties.NAMESPACE_APPLICATION; // ignored; @@ -348,6 +361,18 @@ public class AndroidKeyStoreProvider extends Provider { } descriptor.alias = alias; descriptor.blob = null; + + final AndroidKeyStoreKey key = loadAndroidKeyStoreKeyFromKeystore(keyStore, descriptor); + if (key instanceof AndroidKeyStorePublicKey) { + return ((AndroidKeyStorePublicKey) key).getPrivateKey(); + } else { + return key; + } + } + + private static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore( + @NonNull KeyStore2 keyStore, @NonNull KeyDescriptor descriptor) + throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException { KeyEntryResponse response = null; try { response = keyStore.getKeyEntry(descriptor); @@ -397,7 +422,7 @@ public class AndroidKeyStoreProvider extends Provider { keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) { return makeAndroidKeyStorePublicKeyFromKeyEntryResponse(descriptor, response.metadata, new KeyStoreSecurityLevel(response.iSecurityLevel), - keymasterAlgorithm).getPrivateKey(); + keymasterAlgorithm); } else { throw new UnrecoverableKeyException("Key algorithm unknown"); } diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index dc467c41baed..41ecd5e49acd 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -401,10 +401,11 @@ struct DrawImageLattice final : Op { struct DrawTextBlob final : Op { static const auto kType = Type::DrawTextBlob; DrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) - : blob(sk_ref_sp(blob)), x(x), y(y), paint(paint) {} + : blob(sk_ref_sp(blob)), x(x), y(y), paint(paint), drawTextBlobMode(gDrawTextBlobMode) {} sk_sp<const SkTextBlob> blob; SkScalar x, y; SkPaint paint; + DrawTextBlobMode drawTextBlobMode; void draw(SkCanvas* c, const SkMatrix&) const { c->drawTextBlob(blob.get(), x, y, paint); } }; @@ -791,6 +792,24 @@ constexpr color_transform_fn colorTransformForOp() { } } +template<> +constexpr color_transform_fn colorTransformForOp<DrawTextBlob>() { + return [](const void *opRaw, ColorTransform transform) { + const DrawTextBlob *op = reinterpret_cast<const DrawTextBlob*>(opRaw); + switch (op->drawTextBlobMode) { + case DrawTextBlobMode::HctOutline: + const_cast<SkPaint&>(op->paint).setColor(SK_ColorBLACK); + break; + case DrawTextBlobMode::HctInner: + const_cast<SkPaint&>(op->paint).setColor(SK_ColorWHITE); + break; + default: + transformPaint(transform, const_cast<SkPaint*>(&(op->paint))); + break; + } + }; +} + #define X(T) colorTransformForOp<T>(), static const color_transform_fn color_transform_fns[] = { #include "DisplayListOps.in" diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp index c138a32eacc2..14906d5c1166 100644 --- a/libs/hwui/hwui/Canvas.cpp +++ b/libs/hwui/hwui/Canvas.cpp @@ -111,6 +111,7 @@ public: bool darken = channelSum < (128 * 3); // outline + gDrawTextBlobMode = DrawTextBlobMode::HctOutline; Paint outlinePaint(paint); simplifyPaint(darken ? SK_ColorWHITE : SK_ColorBLACK, &outlinePaint); outlinePaint.setStyle(SkPaint::kStrokeAndFill_Style); @@ -118,11 +119,14 @@ public: bounds.mRight, bounds.mBottom, totalAdvance); // inner + gDrawTextBlobMode = DrawTextBlobMode::HctInner; Paint innerPaint(paint); simplifyPaint(darken ? SK_ColorBLACK : SK_ColorWHITE, &innerPaint); innerPaint.setStyle(SkPaint::kFill_Style); canvas->drawGlyphs(glyphFunc, glyphCount, innerPaint, x, y, bounds.mLeft, bounds.mTop, bounds.mRight, bounds.mBottom, totalAdvance); + + gDrawTextBlobMode = DrawTextBlobMode::Normal; } else { // standard draw path canvas->drawGlyphs(glyphFunc, glyphCount, paint, x, y, bounds.mLeft, bounds.mTop, diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h index 27dfed305a94..d9928059ed30 100644 --- a/libs/hwui/hwui/Canvas.h +++ b/libs/hwui/hwui/Canvas.h @@ -87,6 +87,14 @@ class Bitmap; class Paint; struct Typeface; +enum class DrawTextBlobMode { + Normal, + HctOutline, + HctInner, +}; + +inline DrawTextBlobMode gDrawTextBlobMode = DrawTextBlobMode::Normal; + class ANDROID_API Canvas { public: virtual ~Canvas(){}; diff --git a/media/java/android/media/soundtrigger/OWNERS b/media/java/android/media/soundtrigger/OWNERS index 6a351d396836..e5d037003ac4 100644 --- a/media/java/android/media/soundtrigger/OWNERS +++ b/media/java/android/media/soundtrigger/OWNERS @@ -1 +1,2 @@ +ytai@google.com elaurent@google.com diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java index 4e3085f4704d..b4a651c0607e 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java +++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java @@ -16,6 +16,22 @@ package android.net; +import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -30,6 +46,8 @@ import android.os.Process; import android.text.TextUtils; import android.util.proto.ProtoOutputStream; +import java.util.Arrays; +import java.util.List; import java.util.Objects; import java.util.Set; @@ -154,8 +172,30 @@ public class NetworkRequest implements Parcelable { * needed in terms of {@link NetworkCapabilities} features */ public static class Builder { + /** + * Capabilities that are currently compatible with VCN networks. + */ + private static final List<Integer> VCN_SUPPORTED_CAPABILITIES = Arrays.asList( + NET_CAPABILITY_CAPTIVE_PORTAL, + NET_CAPABILITY_DUN, + NET_CAPABILITY_FOREGROUND, + NET_CAPABILITY_INTERNET, + NET_CAPABILITY_NOT_CONGESTED, + NET_CAPABILITY_NOT_METERED, + NET_CAPABILITY_NOT_RESTRICTED, + NET_CAPABILITY_NOT_ROAMING, + NET_CAPABILITY_NOT_SUSPENDED, + NET_CAPABILITY_NOT_VPN, + NET_CAPABILITY_PARTIAL_CONNECTIVITY, + NET_CAPABILITY_TEMPORARILY_NOT_METERED, + NET_CAPABILITY_TRUSTED, + NET_CAPABILITY_VALIDATED); + private final NetworkCapabilities mNetworkCapabilities; + // A boolean that represents the user modified NOT_VCN_MANAGED capability. + private boolean mModifiedNotVcnManaged = false; + /** * Default constructor for Builder. */ @@ -177,6 +217,7 @@ public class NetworkRequest implements Parcelable { // maybeMarkCapabilitiesRestricted() doesn't add back. final NetworkCapabilities nc = new NetworkCapabilities(mNetworkCapabilities); nc.maybeMarkCapabilitiesRestricted(); + deduceNotVcnManagedCapability(nc); return new NetworkRequest(nc, ConnectivityManager.TYPE_NONE, ConnectivityManager.REQUEST_ID_UNSET, Type.NONE); } @@ -193,6 +234,9 @@ public class NetworkRequest implements Parcelable { */ public Builder addCapability(@NetworkCapabilities.NetCapability int capability) { mNetworkCapabilities.addCapability(capability); + if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) { + mModifiedNotVcnManaged = true; + } return this; } @@ -204,6 +248,9 @@ public class NetworkRequest implements Parcelable { */ public Builder removeCapability(@NetworkCapabilities.NetCapability int capability) { mNetworkCapabilities.removeCapability(capability); + if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) { + mModifiedNotVcnManaged = true; + } return this; } @@ -261,6 +308,9 @@ public class NetworkRequest implements Parcelable { @NonNull public Builder clearCapabilities() { mNetworkCapabilities.clearAll(); + // If the caller explicitly clear all capabilities, the NOT_VCN_MANAGED capabilities + // should not be add back later. + mModifiedNotVcnManaged = true; return this; } @@ -380,6 +430,25 @@ public class NetworkRequest implements Parcelable { mNetworkCapabilities.setSignalStrength(signalStrength); return this; } + + /** + * Deduce the NET_CAPABILITY_NOT_VCN_MANAGED capability from other capabilities + * and user intention, which includes: + * 1. For the requests that don't have anything besides + * {@link #VCN_SUPPORTED_CAPABILITIES}, add the NET_CAPABILITY_NOT_VCN_MANAGED to + * allow the callers automatically utilize VCN networks if available. + * 2. For the requests that explicitly add or remove NET_CAPABILITY_NOT_VCN_MANAGED, + * do not alter them to allow user fire request that suits their need. + * + * @hide + */ + private void deduceNotVcnManagedCapability(final NetworkCapabilities nc) { + if (mModifiedNotVcnManaged) return; + for (final int cap : nc.getCapabilities()) { + if (!VCN_SUPPORTED_CAPABILITIES.contains(cap)) return; + } + nc.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); + } } // implement the Parcelable interface diff --git a/packages/Connectivity/framework/src/android/net/NetworkUtils.java b/packages/Connectivity/framework/src/android/net/NetworkUtils.java index 9ccb04a44af4..b5e8a614b8ea 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkUtils.java +++ b/packages/Connectivity/framework/src/android/net/NetworkUtils.java @@ -91,7 +91,8 @@ public class NetworkUtils { * this socket will go directly to the underlying network, so its traffic will not be * forwarded through the VPN. */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553, + publicAlternatives = "Use {@link android.net.VpnService#protect} instead.") public static native boolean protectFromVpn(FileDescriptor fd); /** diff --git a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java index 0242ba08742c..340141b78aa5 100644 --- a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java +++ b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. diff --git a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java index 85e3fa3048ed..43fffd733e91 100644 --- a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java +++ b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java @@ -40,6 +40,8 @@ import com.android.internal.annotations.VisibleForTesting; import java.util.Arrays; import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; /** * A class to encapsulate management of the "Smart Networking" capability of @@ -73,6 +75,32 @@ public class MultinetworkPolicyTracker { private volatile int mMeteredMultipathPreference; private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + // Mainline module can't use internal HandlerExecutor, so add an identical executor here. + private static class HandlerExecutor implements Executor { + @NonNull + private final Handler mHandler; + + HandlerExecutor(@NonNull Handler handler) { + mHandler = handler; + } + @Override + public void execute(Runnable command) { + if (!mHandler.post(command)) { + throw new RejectedExecutionException(mHandler + " is shutting down"); + } + } + } + + @VisibleForTesting + protected class ActiveDataSubscriptionIdChangedListener extends PhoneStateListener + implements PhoneStateListener.ActiveDataSubscriptionIdChangedListener { + @Override + public void onActiveDataSubscriptionIdChanged(int subId) { + mActiveSubId = subId; + reevaluateInternal(); + } + } + public MultinetworkPolicyTracker(Context ctx, Handler handler) { this(ctx, handler, null); } @@ -93,14 +121,8 @@ public class MultinetworkPolicyTracker { } }; - ctx.getSystemService(TelephonyManager.class).listen( - new PhoneStateListener(handler.getLooper()) { - @Override - public void onActiveDataSubscriptionIdChanged(int subId) { - mActiveSubId = subId; - reevaluateInternal(); - } - }, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); + ctx.getSystemService(TelephonyManager.class).registerPhoneStateListener( + new HandlerExecutor(handler), new ActiveDataSubscriptionIdChangedListener()); updateAvoidBadWifi(); updateMeteredMultipathPreference(); diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index c3fc019c6787..cd7449ad0d8e 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -336,6 +336,9 @@ <!-- Permissions required for CTS test - AdbManagerTest --> <uses-permission android:name="android.permission.MANAGE_DEBUGGING" /> + <!-- Permission required for CTS test - CtsTelephonyTestCases --> + <uses-permission android:name="android.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE" /> + <!-- Permission needed for CTS test - DisplayTest --> <uses-permission android:name="android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS" /> diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS b/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS new file mode 100644 index 000000000000..9b3e386bc0d8 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS @@ -0,0 +1,12 @@ +# Scroll Capture (Long Screenshots) +# Bug component: 801322 +# +# Referenced by: +# +# core/java/src/android/view/OWNERS +# core/java/src/com/android/internal/view/OWNERS +# core/tests/coretests/src/android/view/OWNERS +# core/tests/coretests/src/com/android/internal/view/OWNERS + +mrcasey@google.com +mrenouf@google.com diff --git a/services/Android.bp b/services/Android.bp index 8369444d1615..872b1187a2de 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -22,7 +22,7 @@ filegroup { } filegroup { - name: "services-all-sources", + name: "services-non-updatable-sources", srcs: [ ":services.core-sources", ":services.accessibility-sources", @@ -47,6 +47,14 @@ filegroup { ":services.usb-sources", ":services.voiceinteraction-sources", ":services.wifi-sources", + ], + visibility: ["//visibility:private"], +} + +filegroup { + name: "services-all-sources", + srcs: [ + ":services-non-updatable-sources", ":service-permission-sources", ":service-statsd-sources", ], @@ -127,9 +135,8 @@ filegroup { // API stub // ============================================================= -droidstubs { - name: "services-stubs.sources", - srcs: [":services-all-sources"], +stubs_defaults { + name: "services-stubs-default", installable: false, args: " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\)" + " --hide-annotation android.annotation.Hide" + @@ -139,7 +146,13 @@ droidstubs { " --hide DeprecationMismatch" + " --hide HiddenTypedefConstant", visibility: ["//visibility:private"], - filter_packages: ["com.android."], + filter_packages: ["com.android."] +} + +droidstubs { + name: "services-stubs.sources", + srcs: [":services-all-sources"], + defaults: ["services-stubs-default"], check_api: { current: { api_file: "api/current.txt", @@ -185,3 +198,34 @@ java_library { dir: "apistubs/android/system-server", }, } + +droidstubs { + name: "services-non-updatable-stubs.sources", + srcs: [":services-non-updatable-sources"], + defaults: ["services-stubs-default"], + check_api: { + current: { + api_file: "api/non-updatable-current.txt", + removed_api_file: "api/non-updatable-removed.txt", + }, + api_lint: { + enabled: true, + new_since: ":android-non-updatable.api.system-server.latest", + baseline_file: "api/non-updatable-lint-baseline.txt", + }, + }, + dists: [ + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/system-server/api", + dest: "android-non-updatable.txt", + tag: ".api.txt" + }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/system-server/api", + dest: "android-non-updatable-removed.tx", + tag: ".removed-api.txt", + }, + ] +}
\ No newline at end of file diff --git a/services/api/Android.bp b/services/api/Android.bp new file mode 100644 index 000000000000..b8ca5488c5cd --- /dev/null +++ b/services/api/Android.bp @@ -0,0 +1,29 @@ +// 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 { + default_visibility: ["//visibility:private"], +} + +filegroup { + name: "non-updatable-system-server-current.txt", + srcs: ["non-updatable-current.txt"], + visibility: ["//frameworks/base/api"], +} + +filegroup { + name: "non-updatable-system-server-removed.txt", + srcs: ["non-updatable-removed.txt"], + visibility: ["//frameworks/base/api"], +}
\ No newline at end of file diff --git a/services/api/current.txt b/services/api/current.txt index 9bbb3efcc7c2..17ca369c62ab 100644 --- a/services/api/current.txt +++ b/services/api/current.txt @@ -46,6 +46,11 @@ package com.android.role.persistence { package com.android.server { + public final class LocalManagerRegistry { + method public static <T> void addManager(@NonNull Class<T>, @NonNull T); + method @Nullable public static <T> T getManager(@NonNull Class<T>); + } + public abstract class SystemService { ctor public SystemService(@NonNull android.content.Context); method @NonNull public final android.content.Context getContext(); diff --git a/services/api/non-updatable-current.txt b/services/api/non-updatable-current.txt new file mode 100644 index 000000000000..647739f34cf2 --- /dev/null +++ b/services/api/non-updatable-current.txt @@ -0,0 +1,46 @@ +// Signature format: 2.0 +package com.android.server { + + public final class LocalManagerRegistry { + method public static <T> void addManager(@NonNull Class<T>, @NonNull T); + method @Nullable public static <T> T getManager(@NonNull Class<T>); + } + + public abstract class SystemService { + ctor public SystemService(@NonNull android.content.Context); + method @NonNull public final android.content.Context getContext(); + method public boolean isUserSupported(@NonNull com.android.server.SystemService.TargetUser); + method public void onBootPhase(int); + method public abstract void onStart(); + method public void onUserStarting(@NonNull com.android.server.SystemService.TargetUser); + method public void onUserStopped(@NonNull com.android.server.SystemService.TargetUser); + method public void onUserStopping(@NonNull com.android.server.SystemService.TargetUser); + method public void onUserSwitching(@Nullable com.android.server.SystemService.TargetUser, @NonNull com.android.server.SystemService.TargetUser); + method public void onUserUnlocked(@NonNull com.android.server.SystemService.TargetUser); + method public void onUserUnlocking(@NonNull com.android.server.SystemService.TargetUser); + method protected final void publishBinderService(@NonNull String, @NonNull android.os.IBinder); + method protected final void publishBinderService(@NonNull String, @NonNull android.os.IBinder, boolean); + field public static final int PHASE_ACTIVITY_MANAGER_READY = 550; // 0x226 + field public static final int PHASE_BOOT_COMPLETED = 1000; // 0x3e8 + field public static final int PHASE_DEVICE_SPECIFIC_SERVICES_READY = 520; // 0x208 + field public static final int PHASE_LOCK_SETTINGS_READY = 480; // 0x1e0 + field public static final int PHASE_SYSTEM_SERVICES_READY = 500; // 0x1f4 + field public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600; // 0x258 + field public static final int PHASE_WAIT_FOR_DEFAULT_DISPLAY = 100; // 0x64 + } + + public static final class SystemService.TargetUser { + method @NonNull public android.os.UserHandle getUserHandle(); + } + +} + +package com.android.server.wifi { + + public class SupplicantManager { + method public static void start(); + method public static void stop(); + } + +} + diff --git a/services/api/non-updatable-lint-baseline.txt b/services/api/non-updatable-lint-baseline.txt new file mode 100644 index 000000000000..b46d21edd44c --- /dev/null +++ b/services/api/non-updatable-lint-baseline.txt @@ -0,0 +1,9 @@ +// Baseline format: 1.0 +NotCloseable: com.android.server.wifi.SupplicantManager: + Classes that release resources (stop()) should implement AutoClosable and CloseGuard: class com.android.server.wifi.SupplicantManager + + +ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder): + Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder)} +ProtectedMember: com.android.server.SystemService#publishBinderService(String, android.os.IBinder, boolean): + Protected methods not allowed; must be public: method com.android.server.SystemService.publishBinderService(String,android.os.IBinder,boolean)} diff --git a/services/api/non-updatable-removed.txt b/services/api/non-updatable-removed.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/services/api/non-updatable-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index f4138d10a84d..542d527177a1 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -44,6 +44,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE; @@ -91,7 +92,6 @@ import android.net.IConnectivityManager; import android.net.IDnsResolver; import android.net.INetd; import android.net.INetworkActivityListener; -import android.net.INetworkManagementEventObserver; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; import android.net.INetworkPolicyListener; @@ -194,6 +194,7 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.LocationPermissionChecker; import com.android.internal.util.MessageUtils; import com.android.modules.utils.BasicShellCommandHandler; +import com.android.net.module.util.BaseNetdUnsolicitedEventListener; import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.LinkPropertiesUtils.CompareOrUpdateResult; import com.android.net.module.util.LinkPropertiesUtils.CompareResult; @@ -214,7 +215,6 @@ import com.android.server.connectivity.NetworkRanker; import com.android.server.connectivity.PermissionMonitor; import com.android.server.connectivity.ProxyTracker; import com.android.server.connectivity.QosCallbackTracker; -import com.android.server.net.BaseNetworkObserver; import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.utils.PriorityDump; @@ -332,6 +332,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private INetworkStatsService mStatsService; private NetworkPolicyManager mPolicyManager; private NetworkPolicyManagerInternal mPolicyManagerInternal; + private final NetdCallback mNetdCallback; /** * TestNetworkService (lazily) created upon first usage. Locked to prevent creation of multiple @@ -1204,6 +1205,13 @@ public class ConnectivityService extends IConnectivityManager.Stub mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNMS, mNetd); + mNetdCallback = new NetdCallback(); + try { + mNetd.registerUnsolicitedEventListener(mNetdCallback); + } catch (RemoteException | ServiceSpecificException e) { + loge("Error registering event listener :" + e); + } + mSettingsObserver = new SettingsObserver(mContext, mHandler); registerSettingsCallbacks(); @@ -1241,6 +1249,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) { final NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addCapability(NET_CAPABILITY_INTERNET); + netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); netCap.removeCapability(NET_CAPABILITY_NOT_VPN); netCap.setSingleUid(uid); return netCap; @@ -1255,6 +1264,7 @@ public class ConnectivityService extends IConnectivityManager.Stub int transportType, NetworkRequest.Type type) { final NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addCapability(NET_CAPABILITY_INTERNET); + netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName()); if (transportType > TYPE_NONE) { netCap.addTransportType(transportType); @@ -8649,6 +8659,14 @@ public class ConnectivityService extends IConnectivityManager.Stub notifyDataStallSuspected(p, network.getNetId()); } + private class NetdCallback extends BaseNetdUnsolicitedEventListener { + @Override + public void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, + long timestampNs, int uid) { + mNetworkActivityTracker.setAndReportNetworkActive(isActive, timerLabel, timestampNs); + } + } + private final LegacyNetworkActivityTracker mNetworkActivityTracker; /** @@ -8659,7 +8677,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final int NO_UID = -1; private final Context mContext; private final INetd mNetd; - private final INetworkManagementService mNMS; private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners = new RemoteCallbackList<>(); // Indicate the current system default network activity is active or not. @@ -8682,41 +8699,27 @@ public class ConnectivityService extends IConnectivityManager.Stub LegacyNetworkActivityTracker(@NonNull Context context, @NonNull Handler handler, @NonNull INetworkManagementService nms, @NonNull INetd netd) { mContext = context; - mNMS = nms; mNetd = netd; mHandler = handler; - try { - mNMS.registerObserver(mDataActivityObserver); - } catch (RemoteException e) { - loge("Error registering observer :" + e); - } - } - - // TODO: Migrate away the dependency with INetworkManagementEventObserver. - private final INetworkManagementEventObserver mDataActivityObserver = - new BaseNetworkObserver() { - @Override - public void interfaceClassDataActivityChanged(int transportType, boolean active, - long tsNanos, int uid) { - sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active, - tsNanos); - synchronized (mActiveIdleTimers) { - mNetworkActive = active; - // If there are no idle timers, it means that system is not monitoring - // activity, so the system default network for those default network - // unspecified apps is always considered active. - // - // TODO: If the mActiveIdleTimers is empty, netd will actually not send - // any network activity change event. Whenever this event is received, - // the mActiveIdleTimers should be always not empty. The legacy behavior - // is no-op. Remove to refer to mNetworkActive only. - if (mNetworkActive || mActiveIdleTimers.isEmpty()) { - mHandler.sendMessage( - mHandler.obtainMessage(EVENT_REPORT_NETWORK_ACTIVITY)); - } - } - } - }; + } + + public void setAndReportNetworkActive(boolean active, int transportType, long tsNanos) { + sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active, tsNanos); + synchronized (mActiveIdleTimers) { + mNetworkActive = active; + // If there are no idle timers, it means that system is not monitoring + // activity, so the system default network for those default network + // unspecified apps is always considered active. + // + // TODO: If the mActiveIdleTimers is empty, netd will actually not send + // any network activity change event. Whenever this event is received, + // the mActiveIdleTimers should be always not empty. The legacy behavior + // is no-op. Remove to refer to mNetworkActive only. + if (mNetworkActive || mActiveIdleTimers.isEmpty()) { + mHandler.sendMessage(mHandler.obtainMessage(EVENT_REPORT_NETWORK_ACTIVITY)); + } + } + } // The network activity should only be updated from ConnectivityService handler thread // when mActiveIdleTimers lock is held. diff --git a/services/core/java/com/android/server/LocalManagerRegistry.java b/services/core/java/com/android/server/LocalManagerRegistry.java new file mode 100644 index 000000000000..85795fff61ee --- /dev/null +++ b/services/core/java/com/android/server/LocalManagerRegistry.java @@ -0,0 +1,73 @@ +/* + * 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; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.util.ArrayMap; + +import java.util.Map; +import java.util.Objects; + +/** + * The registry for in-process module interfaces. + * <p> + * In-process module interfaces should be named with the suffix {@code ManagerLocal} for + * consistency. + * + * @hide + */ +@SystemApi(client = SystemApi.Client.SYSTEM_SERVER) +public final class LocalManagerRegistry { + private LocalManagerRegistry() {} + + @NonNull + private static final Map<Class<?>, Object> sManagers = new ArrayMap<>(); + + /** + * Get a manager from the registry. + * + * @param managerClass the class that the manager implements + * @return the manager, or {@code null} if not found + */ + @Nullable + @SuppressWarnings("unchecked") + public static <T> T getManager(@NonNull Class<T> managerClass) { + synchronized (sManagers) { + return (T) sManagers.get(managerClass); + } + } + + /** + * Adds a manager to the registry. + * + * @param managerClass the class that the manager implements + * @param manager the manager + * @throws IllegalStateException if the manager class is already registered + */ + public static <T> void addManager(@NonNull Class<T> managerClass, @NonNull T manager) { + Objects.requireNonNull(managerClass, "managerClass"); + Objects.requireNonNull(manager, "manager"); + synchronized (sManagers) { + if (sManagers.containsKey(managerClass)) { + throw new IllegalStateException(managerClass.getName() + " is already registered"); + } + sManagers.put(managerClass, manager); + } + } +} diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING index a927fa2c4bd4..0ea88f44c0b4 100644 --- a/services/core/java/com/android/server/TEST_MAPPING +++ b/services/core/java/com/android/server/TEST_MAPPING @@ -36,7 +36,9 @@ } ], "file_patterns": ["NotificationManagerService\\.java"] - }, + } + ], + "presubmit-large": [ { "name": "CtsScopedStorageHostTest", "file_patterns": ["StorageManagerService\\.java"] diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 81d2b831dc3c..93f14328b50b 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -312,9 +312,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private List<PhysicalChannelConfig> mPhysicalChannelConfigs; - private boolean mIsDataEnabled = false; + private boolean[] mIsDataEnabled; - private int mDataEnabledReason; + private int[] mDataEnabledReason; /** * Per-phone map of precise data connection state. The key of the map is the pair of transport @@ -521,6 +521,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mOutgoingCallEmergencyNumber = copyOf(mOutgoingCallEmergencyNumber, mNumPhones); mOutgoingSmsEmergencyNumber = copyOf(mOutgoingSmsEmergencyNumber, mNumPhones); mTelephonyDisplayInfos = copyOf(mTelephonyDisplayInfos, mNumPhones); + mIsDataEnabled= copyOf(mIsDataEnabled, mNumPhones); + mDataEnabledReason = copyOf(mDataEnabledReason, mNumPhones); // ds -> ss switch. if (mNumPhones < oldNumPhones) { @@ -563,6 +565,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mBarringInfo.add(i, new BarringInfo()); mTelephonyDisplayInfos[i] = null; mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build()); + mIsDataEnabled[i] = false; + mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER; } } @@ -622,6 +626,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mBarringInfo = new ArrayList<>(); mTelephonyDisplayInfos = new TelephonyDisplayInfo[numPhones]; mPhysicalChannelConfigs = new ArrayList<>(); + mIsDataEnabled = new boolean[numPhones]; + mDataEnabledReason = new int[numPhones]; for (int i = 0; i < numPhones; i++) { mCallState[i] = TelephonyManager.CALL_STATE_IDLE; mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE; @@ -652,6 +658,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mBarringInfo.add(i, new BarringInfo()); mTelephonyDisplayInfos[i] = null; mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build()); + mIsDataEnabled[i] = false; + mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER; } mAppOps = mContext.getSystemService(AppOpsManager.class); @@ -1146,7 +1154,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if (events.contains( PhoneStateListener.EVENT_DATA_ENABLED_CHANGED)) { try { - r.callback.onDataEnabledChanged(mIsDataEnabled, mDataEnabledReason); + r.callback.onDataEnabledChanged( + mIsDataEnabled[phoneId], mDataEnabledReason[phoneId]); } catch (RemoteException ex) { remove(r.binder); } @@ -2358,30 +2367,36 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { /** * Notify that the data enabled has changed. * + * @param phoneId the phone id. + * @param subId the subId. * @param enabled True if data is enabled, otherwise disabled. * @param reason Reason for data enabled/disabled. See {@code DATA_*} in * {@link TelephonyManager}. */ - public void notifyDataEnabled(boolean enabled, + public void notifyDataEnabled(int phoneId, int subId, boolean enabled, @TelephonyManager.DataEnabledReason int reason) { if (!checkNotifyPermission("notifyDataEnabled()")) { return; } if (VDBG) { - log("notifyDataEnabled: enabled=" + enabled + " reason=" + reason); + log("notifyDataEnabled: PhoneId=" + phoneId + " subId=" + subId + + " enabled=" + enabled + " reason=" + reason); } - mIsDataEnabled = enabled; - mDataEnabledReason = reason; synchronized (mRecords) { - for (Record r : mRecords) { - if (r.matchPhoneStateListenerEvent( - PhoneStateListener.EVENT_DATA_ENABLED_CHANGED)) { - try { - r.callback.onDataEnabledChanged(enabled, reason); - } catch (RemoteException ex) { - mRemoveList.add(r.binder); + if (validatePhoneId(phoneId)) { + mIsDataEnabled[phoneId] = enabled; + mDataEnabledReason[phoneId] = reason; + for (Record r : mRecords) { + if (r.matchPhoneStateListenerEvent( + PhoneStateListener.EVENT_DATA_ENABLED_CHANGED) + && idMatch(r.subId, subId, phoneId)) { + try { + r.callback.onDataEnabledChanged(enabled, reason); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } } } } @@ -2431,6 +2446,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mOutgoingSmsEmergencyNumber=" + mOutgoingSmsEmergencyNumber[i]); pw.println("mBarringInfo=" + mBarringInfo.get(i)); pw.println("mTelephonyDisplayInfo=" + mTelephonyDisplayInfos[i]); + pw.println("mIsDataEnabled=" + mIsDataEnabled); + pw.println("mDataEnabledReason=" + mDataEnabledReason); pw.decreaseIndent(); } pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState); @@ -2441,8 +2458,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mDefaultPhoneId=" + mDefaultPhoneId); pw.println("mDefaultSubId=" + mDefaultSubId); pw.println("mPhysicalChannelConfigs=" + mPhysicalChannelConfigs); - pw.println("mIsDataEnabled=" + mIsDataEnabled); - pw.println("mDataEnabledReason=" + mDataEnabledReason); pw.decreaseIndent(); diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java index 329ab9983c90..8d5d3d939e4b 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -16,6 +16,8 @@ package com.android.server; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE; + import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; @@ -837,7 +839,10 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Notify all registered StatusCallbacks for this subGroup for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { if (isCallbackPermissioned(cbInfo)) { - Binder.withCleanCallingIdentity(() -> cbInfo.mCallback.onEnteredSafeMode()); + Binder.withCleanCallingIdentity( + () -> + cbInfo.mCallback.onVcnStatusChanged( + VCN_STATUS_CODE_SAFE_MODE)); } } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 900871dfbbb4..e4d2382574ba 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -183,6 +183,7 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.app.ProcessMemoryState; import android.app.ProfilerInfo; +import android.app.PropertyInvalidatedCache; import android.app.WaitResult; import android.app.backup.IBackupManager; import android.app.usage.UsageEvents; @@ -8213,11 +8214,20 @@ public class ActivityManagerService extends IActivityManager.Stub false /* mountExtStorageFull */, abiOverride, zygotePolicyFlags); } - // TODO: Move to ProcessList? @GuardedBy("this") final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated, boolean disableHiddenApiChecks, boolean mountExtStorageFull, String abiOverride, int zygotePolicyFlags) { + return addAppLocked(info, customProcess, isolated, disableHiddenApiChecks, + false /* disableTestApiChecks */, mountExtStorageFull, abiOverride, + zygotePolicyFlags); + } + + // TODO: Move to ProcessList? + @GuardedBy("this") + final ProcessRecord addAppLocked(ApplicationInfo info, String customProcess, boolean isolated, + boolean disableHiddenApiChecks, boolean disableTestApiChecks, + boolean mountExtStorageFull, String abiOverride, int zygotePolicyFlags) { ProcessRecord app; if (!isolated) { app = getProcessRecordLocked(customProcess != null ? customProcess : info.processName, @@ -8252,7 +8262,8 @@ public class ActivityManagerService extends IActivityManager.Stub mPersistentStartingProcesses.add(app); mProcessList.startProcessLocked(app, new HostingRecord("added application", customProcess != null ? customProcess : app.processName), - zygotePolicyFlags, disableHiddenApiChecks, mountExtStorageFull, abiOverride); + zygotePolicyFlags, disableHiddenApiChecks, disableTestApiChecks, + mountExtStorageFull, abiOverride); } return app; @@ -12834,6 +12845,10 @@ public class ActivityManagerService extends IActivityManager.Stub if (r.thread != null) { pw.println("\n\n** Cache info for pid " + r.pid + " [" + r.processName + "] **"); pw.flush(); + if (r.pid == MY_PID) { + PropertyInvalidatedCache.dumpCacheInfo(fd, args); + continue; + } try { TransferPipe tp = new TransferPipe(); try { @@ -13371,6 +13386,8 @@ public class ActivityManagerService extends IActivityManager.Stub } endTime = SystemClock.currentThreadTimeMillis(); hasSwapPss = mi.hasSwappedOutPss; + memtrackGraphics = mi.getOtherPrivate(Debug.MemoryInfo.OTHER_GRAPHICS); + memtrackGl = mi.getOtherPrivate(Debug.MemoryInfo.OTHER_GL); } else { reportType = ProcessStats.ADD_PSS_EXTERNAL; startTime = SystemClock.currentThreadTimeMillis(); @@ -13524,6 +13541,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (!Debug.getMemoryInfo(st.pid, mi)) { continue; } + memtrackGraphics = mi.getOtherPrivate(Debug.MemoryInfo.OTHER_GRAPHICS); + memtrackGl = mi.getOtherPrivate(Debug.MemoryInfo.OTHER_GL); } else { long pss = Debug.getPss(st.pid, tmpLong, memtrackTmp); if (pss == 0) { @@ -14424,6 +14443,8 @@ public class ActivityManagerService extends IActivityManager.Stub }); } final int statsCount = stats.size(); + long totalMemtrackGraphics = 0; + long totalMemtrackGl = 0; for (int i = 0; i < statsCount; i++) { ProcessCpuTracker.Stats st = stats.get(i); long pss = Debug.getPss(st.pid, swaptrackTmp, memtrackTmp); @@ -14434,6 +14455,8 @@ public class ActivityManagerService extends IActivityManager.Stub mi.pss = pss; mi.swapPss = swaptrackTmp[1]; mi.memtrack = memtrackTmp[0]; + totalMemtrackGraphics += memtrackTmp[1]; + totalMemtrackGl += memtrackTmp[2]; memInfos.add(mi); } } @@ -14442,20 +14465,18 @@ public class ActivityManagerService extends IActivityManager.Stub long totalPss = 0; long totalSwapPss = 0; long totalMemtrack = 0; - long totalMemtrackGraphics = 0; - long totalMemtrackGl = 0; for (int i=0, N=memInfos.size(); i<N; i++) { ProcessMemInfo mi = memInfos.get(i); if (mi.pss == 0) { mi.pss = Debug.getPss(mi.pid, swaptrackTmp, memtrackTmp); mi.swapPss = swaptrackTmp[1]; mi.memtrack = memtrackTmp[0]; + totalMemtrackGraphics += memtrackTmp[1]; + totalMemtrackGl += memtrackTmp[2]; } totalPss += mi.pss; totalSwapPss += mi.swapPss; totalMemtrack += mi.memtrack; - totalMemtrackGraphics += memtrackTmp[1]; - totalMemtrackGl += memtrackTmp[2]; } Collections.sort(memInfos, new Comparator<ProcessMemInfo>() { @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) { @@ -17058,12 +17079,11 @@ public class ActivityManagerService extends IActivityManager.Stub || (flags & INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0; boolean disableTestApiChecks = disableHiddenApiChecks || (flags & INSTR_FLAG_DISABLE_TEST_API_CHECKS) != 0; - if (disableHiddenApiChecks || disableTestApiChecks) { enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS, "disable hidden API checks"); - enableTestApiAccess(ai.packageName); + enableTestApiAccess(ii.packageName); } // TODO(b/158750470): remove @@ -17081,7 +17101,8 @@ public class ActivityManagerService extends IActivityManager.Stub } ProcessRecord app = addAppLocked(ai, defProcess, false, disableHiddenApiChecks, - mountExtStorageFull, abiOverride, ZYGOTE_POLICY_FLAG_EMPTY); + disableTestApiChecks, mountExtStorageFull, abiOverride, + ZYGOTE_POLICY_FLAG_EMPTY); app.setActiveInstrumentation(activeInstr); activeInstr.mFinished = false; activeInstr.mSourceUid = callingUid; diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index e2c020af1b02..c5a6e7b83859 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -367,6 +367,13 @@ public final class ProcessList { private static final long NATIVE_MEMTAG_SYNC = 177438394; // This is a bug id. /** + * Enable automatic zero-initialization of native heap memory allocations. + */ + @ChangeId + @Disabled + private static final long NATIVE_HEAP_ZERO_INIT = 178038272; // This is a bug id. + + /** * Enable sampled memory bug detection in the app. * @see <a href="https://source.android.com/devices/tech/debug/gwp-asan">GWP-ASan</a>. */ @@ -1687,12 +1694,28 @@ public final class ProcessList { return gidArray; } - // Returns the memory tagging level to be enabled. If memory tagging isn't - // requested, returns zero. - private int getMemtagLevel(ProcessRecord app) { - // Ensure the hardware + kernel actually supports MTE. - if (!Zygote.nativeSupportsMemoryTagging()) { - return 0; + private int memtagModeToZygoteMemtagLevel(int memtagMode) { + switch (memtagMode) { + case ApplicationInfo.MEMTAG_ASYNC: + return Zygote.MEMORY_TAG_LEVEL_ASYNC; + case ApplicationInfo.MEMTAG_SYNC: + return Zygote.MEMORY_TAG_LEVEL_SYNC; + default: + return Zygote.MEMORY_TAG_LEVEL_NONE; + } + } + + // Returns the requested memory tagging level. + private int getRequestedMemtagLevel(ProcessRecord app) { + // Look at the process attribute first. + if (app.processInfo != null + && app.processInfo.memtagMode != ApplicationInfo.MEMTAG_DEFAULT) { + return memtagModeToZygoteMemtagLevel(app.processInfo.memtagMode); + } + + // Then at the application attribute. + if (app.info.getMemtagMode() != ApplicationInfo.MEMTAG_DEFAULT) { + return memtagModeToZygoteMemtagLevel(app.info.getMemtagMode()); } if (mPlatformCompat.isChangeEnabled(NATIVE_MEMTAG_SYNC, app.info)) { @@ -1703,40 +1726,43 @@ public final class ProcessList { return Zygote.MEMORY_TAG_LEVEL_ASYNC; } - return 0; - } - - private boolean shouldEnableTaggedPointers(ProcessRecord app) { - // Ensure we have platform + kernel support for TBI. - if (!Zygote.nativeSupportsTaggedPointers()) { - return false; - } - // Check to ensure the app hasn't explicitly opted-out of TBI via. the manifest attribute. if (!app.info.allowsNativeHeapPointerTagging()) { - return false; + return Zygote.MEMORY_TAG_LEVEL_NONE; } // Check to see that the compat feature for TBI is enabled. - if (!mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING, app.info)) { - return false; + if (mPlatformCompat.isChangeEnabled(NATIVE_HEAP_POINTER_TAGGING, app.info)) { + return Zygote.MEMORY_TAG_LEVEL_TBI; } - return true; + return Zygote.MEMORY_TAG_LEVEL_NONE; } private int decideTaggingLevel(ProcessRecord app) { - // Check MTE support first, as it should take precedence over TBI. - int memtagLevel = getMemtagLevel(app); - if (memtagLevel != 0) { - return memtagLevel; - } - - if (shouldEnableTaggedPointers(app)) { - return Zygote.MEMORY_TAG_LEVEL_TBI; + // Get the desired tagging level (app manifest + compat features). + int level = getRequestedMemtagLevel(app); + + // Take into account the hardware capabilities. + if (Zygote.nativeSupportsMemoryTagging()) { + // MTE devices can not do TBI, because the Zygote process already has live MTE + // allocations. Downgrade TBI to NONE. + if (level == Zygote.MEMORY_TAG_LEVEL_TBI) { + level = Zygote.MEMORY_TAG_LEVEL_NONE; + } + } else if (Zygote.nativeSupportsTaggedPointers()) { + // TBI-but-not-MTE devices downgrade MTE modes to TBI. + // The idea is that if an app opts into full hardware tagging (MTE), it must be ok with + // the "fake" pointer tagging (TBI). + if (level == Zygote.MEMORY_TAG_LEVEL_ASYNC || level == Zygote.MEMORY_TAG_LEVEL_SYNC) { + level = Zygote.MEMORY_TAG_LEVEL_TBI; + } + } else { + // Otherwise disable all tagging. + level = Zygote.MEMORY_TAG_LEVEL_NONE; } - return 0; + return level; } private int decideGwpAsanLevel(ProcessRecord app) { @@ -1747,7 +1773,7 @@ public final class ProcessList { ? Zygote.GWP_ASAN_LEVEL_ALWAYS : Zygote.GWP_ASAN_LEVEL_NEVER; } - // Then at the applicaton attribute. + // Then at the application attribute. if (app.info.getGwpAsanMode() != ApplicationInfo.GWP_ASAN_DEFAULT) { return app.info.getGwpAsanMode() == ApplicationInfo.GWP_ASAN_ALWAYS ? Zygote.GWP_ASAN_LEVEL_ALWAYS @@ -1764,13 +1790,29 @@ public final class ProcessList { return Zygote.GWP_ASAN_LEVEL_NEVER; } + private boolean enableNativeHeapZeroInit(ProcessRecord app) { + // Look at the process attribute first. + if (app.processInfo != null && app.processInfo.nativeHeapZeroInit != null) { + return app.processInfo.nativeHeapZeroInit; + } + // Then at the application attribute. + if (app.info.isNativeHeapZeroInit() != null) { + return app.info.isNativeHeapZeroInit(); + } + // Compat feature last. + if (mPlatformCompat.isChangeEnabled(NATIVE_HEAP_ZERO_INIT, app.info)) { + return true; + } + return false; + } + /** * @return {@code true} if process start is successful, false otherwise. */ @GuardedBy("mService") boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, - int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean mountExtStorageFull, - String abiOverride) { + int zygotePolicyFlags, boolean disableHiddenApiChecks, boolean disableTestApiChecks, + boolean mountExtStorageFull, String abiOverride) { if (app.pendingStart) { return true; } @@ -1914,6 +1956,10 @@ public final class ProcessList { throw new IllegalStateException("Invalid API policy: " + policy); } runtimeFlags |= policyBits; + + if (disableTestApiChecks) { + runtimeFlags |= Zygote.DISABLE_TEST_API_ENFORCEMENT_POLICY; + } } String useAppImageCache = SystemProperties.get( @@ -1967,6 +2013,10 @@ public final class ProcessList { runtimeFlags |= decideTaggingLevel(app); } + if (enableNativeHeapZeroInit(app)) { + runtimeFlags |= Zygote.NATIVE_HEAP_ZERO_INIT; + } + // the per-user SELinux context must be set if (TextUtils.isEmpty(app.info.seInfoUser)) { Slog.wtf(ActivityManagerService.TAG, "SELinux tag not defined", @@ -2356,7 +2406,8 @@ public final class ProcessList { final boolean startProcessLocked(ProcessRecord app, HostingRecord hostingRecord, int zygotePolicyFlags, String abiOverride) { return startProcessLocked(app, hostingRecord, zygotePolicyFlags, - false /* disableHiddenApiChecks */, false /* mountExtStorageFull */, abiOverride); + false /* disableHiddenApiChecks */, false /* disableTestApiChecks */, + false /* mountExtStorageFull */, abiOverride); } @GuardedBy("mService") diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index c5152c081e70..4775541c6781 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -388,6 +388,9 @@ class ProcessRecord implements WindowProcessListener { if (processInfo.gwpAsanMode != ApplicationInfo.GWP_ASAN_DEFAULT) { pw.print(prefix); pw.println(" gwpAsanMode=" + processInfo.gwpAsanMode); } + if (processInfo.memtagMode != ApplicationInfo.MEMTAG_DEFAULT) { + pw.print(prefix); pw.println(" memtagMode=" + processInfo.memtagMode); + } } pw.print(prefix); pw.print("mRequiredAbi="); pw.print(mRequiredAbi); pw.print(" instructionSet="); pw.println(instructionSet); @@ -645,9 +648,12 @@ class ProcessRecord implements WindowProcessListener { if (processes != null) { procInfo = processes.get(_processName); if (procInfo != null && procInfo.deniedPermissions == null - && procInfo.gwpAsanMode == ApplicationInfo.GWP_ASAN_DEFAULT) { + && procInfo.gwpAsanMode == ApplicationInfo.GWP_ASAN_DEFAULT + && procInfo.memtagMode == ApplicationInfo.MEMTAG_DEFAULT + && procInfo.nativeHeapZeroInit == null) { // If this process hasn't asked for permissions to be denied, or for a - // non-default GwpAsan mode, then we don't care about it. + // non-default GwpAsan mode, or any other non-default setting, then we don't + // care about it. procInfo = null; } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 5a8396ff5886..e78322915229 100755 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -6554,7 +6554,10 @@ public class AudioService extends IAudioService.Stub private void onSetVolumeIndexOnDevice(@NonNull DeviceVolumeUpdate update) { final VolumeStreamState streamState = mStreamStates[update.mStreamType]; if (update.hasVolumeIndex()) { - final int index = update.getVolumeIndex(); + int index = update.getVolumeIndex(); + if (!checkSafeMediaVolume(update.mStreamType, index, update.mDevice)) { + index = safeMediaVolumeIndex(update.mDevice); + } streamState.setIndex(index, update.mDevice, update.mCaller, // trusted as index is always validated before message is posted true /*hasModifyAudioSettings*/); diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java index 422991e082a9..66a652053857 100644 --- a/services/core/java/com/android/server/compat/CompatConfig.java +++ b/services/core/java/com/android/server/compat/CompatConfig.java @@ -50,6 +50,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -595,18 +596,24 @@ final class CompatConfig { * Rechecks all the existing overrides for a package. */ void recheckOverrides(String packageName) { + // Local cache of compat changes. Holding a lock on mChanges for the whole duration of the + // method will cause a deadlock. + List<CompatChange> changes; synchronized (mChanges) { - boolean shouldInvalidateCache = false; + changes = new ArrayList<>(mChanges.size()); for (int idx = 0; idx < mChanges.size(); ++idx) { - CompatChange c = mChanges.valueAt(idx); - OverrideAllowedState allowedState = - mOverrideValidator.getOverrideAllowedState(c.getId(), packageName); - shouldInvalidateCache |= c.recheckOverride(packageName, allowedState, mContext); - } - if (shouldInvalidateCache) { - invalidateCache(); + changes.add(mChanges.valueAt(idx)); } } + boolean shouldInvalidateCache = false; + for (CompatChange c: changes) { + OverrideAllowedState allowedState = + mOverrideValidator.getOverrideAllowedState(c.getId(), packageName); + shouldInvalidateCache |= c.recheckOverride(packageName, allowedState, mContext); + } + if (shouldInvalidateCache) { + invalidateCache(); + } } void registerContentObserver() { diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java index 21ef356c962c..4ecc7594a79c 100644 --- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java +++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java @@ -26,6 +26,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.WARNING_DISABLED; import static android.net.NetworkTemplate.NETWORK_TYPE_ALL; +import static android.net.NetworkTemplate.OEM_MANAGED_ALL; import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -226,7 +227,7 @@ public class MultipathPolicyTracker { mNetworkTemplate = new NetworkTemplate( NetworkTemplate.MATCH_MOBILE, subscriberId, new String[] { subscriberId }, null, NetworkStats.METERED_ALL, NetworkStats.ROAMING_ALL, - NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL); + NetworkStats.DEFAULT_NETWORK_NO, NETWORK_TYPE_ALL, OEM_MANAGED_ALL); mUsageCallback = new UsageCallback() { @Override public void onThresholdReached(int networkType, String subscriberId) { @@ -274,7 +275,8 @@ public class MultipathPolicyTracker { null /* networkId, unused for matching mobile networks */, !nc.hasCapability(NET_CAPABILITY_NOT_ROAMING), !nc.hasCapability(NET_CAPABILITY_NOT_METERED), - false /* defaultNetwork, templates should have DEFAULT_NETWORK_ALL */); + false /* defaultNetwork, templates should have DEFAULT_NETWORK_ALL */, + OEM_MANAGED_ALL); } private long getRemainingDailyBudget(long limitBytes, diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 713ac73aa9b9..01ac81fb2cb5 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -1510,7 +1510,7 @@ public class Vpn { if (start != -1) ranges.add(new UidRange(start, stop)); } else if (disallowedApplications != null) { // Add all ranges for user skipping UIDs for disallowedApplications. - final UidRange userRange = UidRange.createForUser(userId); + final UidRange userRange = UidRange.createForUser(UserHandle.of(userId)); int start = userRange.start; for (int uid : getAppsUids(disallowedApplications, userId)) { if (uid == start) { @@ -1523,7 +1523,7 @@ public class Vpn { if (start <= userRange.stop) ranges.add(new UidRange(start, userRange.stop)); } else { // Add all UIDs for the user. - ranges.add(UidRange.createForUser(userId)); + ranges.add(UidRange.createForUser(UserHandle.of(userId))); } } @@ -1532,7 +1532,7 @@ public class Vpn { private static List<UidRange> uidRangesForUser(int userId, Set<UidRange> existingRanges) { // UidRange#createForUser returns the entire range of UIDs available to a macro-user. // This is something like 0-99999 ; {@see UserHandle#PER_USER_RANGE} - final UidRange userRange = UidRange.createForUser(userId); + final UidRange userRange = UidRange.createForUser(UserHandle.of(userId)); final List<UidRange> ranges = new ArrayList<>(); for (UidRange range : existingRanges) { if (userRange.containsRange(range)) { diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index f1750cd16f1f..294d7e257b6e 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -489,8 +489,8 @@ public class LockSettingsService extends ILockSettings.Stub { return KeyStore.getInstance(); } - public RecoverableKeyStoreManager getRecoverableKeyStoreManager(KeyStore keyStore) { - return RecoverableKeyStoreManager.getInstance(mContext, keyStore); + public RecoverableKeyStoreManager getRecoverableKeyStoreManager() { + return RecoverableKeyStoreManager.getInstance(mContext); } public IStorageManager getStorageManager() { @@ -571,7 +571,7 @@ public class LockSettingsService extends ILockSettings.Stub { mInjector = injector; mContext = injector.getContext(); mKeyStore = injector.getKeyStore(); - mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(mKeyStore); + mRecoverableKeyStoreManager = injector.getRecoverableKeyStoreManager(); mHandler = injector.getHandler(injector.getServiceThread()); mStrongAuth = injector.getStrongAuth(); mActivityManager = injector.getActivityManager(); diff --git a/services/core/java/com/android/server/locksettings/OWNERS b/services/core/java/com/android/server/locksettings/OWNERS index 08b8a8c106b7..7577ee5c9fde 100644 --- a/services/core/java/com/android/server/locksettings/OWNERS +++ b/services/core/java/com/android/server/locksettings/OWNERS @@ -1,3 +1,4 @@ jaggies@google.com kchyn@google.com rubinxu@google.com +xunchang@google.com diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java index 30ea5556b41c..7e00fd69a148 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java @@ -194,7 +194,9 @@ class RebootEscrowManager { } public void reportMetric(boolean success) { - FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, success); + // TODO(b/179105110) design error code; and report the true value for other fields. + FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, 0, 1, 1, + -1, 0); } public RebootEscrowEventLog getEventLog() { diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java index b3b45460899d..697bf08a232e 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java @@ -44,7 +44,7 @@ class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterfa * Use the default lifetime of 10 minutes. The lifetime covers the following activities: * Server wrap secret -> device reboot -> server unwrap blob. */ - private static final long DEFAULT_SERVER_BLOB_LIFETIME_IN_MILLIS = 600_1000; + private static final long DEFAULT_SERVER_BLOB_LIFETIME_IN_MILLIS = 600_000; private final LockSettingsStorage mStorage; diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java index 9857fb637b59..f5941361bd89 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeyStoreProxyImpl.java @@ -16,8 +16,6 @@ package com.android.server.locksettings.recoverablekeystore; -import android.security.keystore2.AndroidKeyStoreProvider; - import java.io.IOException; import java.security.Key; import java.security.KeyStore; @@ -31,22 +29,9 @@ import java.security.cert.CertificateException; */ public class KeyStoreProxyImpl implements KeyStoreProxy { - private final KeyStore mKeyStore; - - /** - * TODO This function redirects keystore access to the legacy keystore during a transitional - * phase during which not all calling code has been adjusted to use Keystore 2.0. - * This can be reverted to a constant of "AndroidKeyStore" when b/171305684 is complete. - * The specific bug for this component is b/171305545. - */ - static String androidKeystoreProviderName() { - if (AndroidKeyStoreProvider.isInstalled()) { - return "AndroidKeyStoreLegacy"; - } else { - return "AndroidKeyStore"; - } + public static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore"; - } + private final KeyStore mKeyStore; /** * A new instance, delegating to {@code keyStore}. @@ -84,7 +69,7 @@ public class KeyStoreProxyImpl implements KeyStoreProxy { * @throws KeyStoreException if there was a problem getting or initializing the key store. */ public static KeyStore getAndLoadAndroidKeyStore() throws KeyStoreException { - KeyStore keyStore = KeyStore.getInstance(androidKeystoreProviderName()); + KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER); try { keyStore.load(/*param=*/ null); } catch (CertificateException | IOException | NoSuchAlgorithmException e) { diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java index 569b7098bb6c..202dfe798616 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java @@ -484,7 +484,7 @@ public class PlatformKeyManager { * @throws KeyStoreException if there was a problem getting or initializing the key store. */ private static KeyStore getAndLoadAndroidKeyStore() throws KeyStoreException { - KeyStore keyStore = KeyStore.getInstance(KeyStoreProxyImpl.androidKeystoreProviderName()); + KeyStore keyStore = KeyStore.getInstance(KeyStoreProxyImpl.ANDROID_KEY_STORE_PROVIDER); try { keyStore.load(/*param=*/ null); } catch (CertificateException | IOException | NoSuchAlgorithmException e) { diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index 6d97ed7a69a7..b49bced4e567 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -34,7 +34,6 @@ import android.os.Binder; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.os.UserHandle; -import android.security.KeyStore; import android.security.keystore.recovery.KeyChainProtectionParams; import android.security.keystore.recovery.KeyChainSnapshot; import android.security.keystore.recovery.RecoveryCertPath; @@ -110,14 +109,14 @@ public class RecoverableKeyStoreManager { * @hide */ public static synchronized RecoverableKeyStoreManager - getInstance(Context context, KeyStore keystore) { + getInstance(Context context) { if (mInstance == null) { RecoverableKeyStoreDb db = RecoverableKeyStoreDb.newInstance(context); PlatformKeyManager platformKeyManager; ApplicationKeyStorage applicationKeyStorage; try { platformKeyManager = PlatformKeyManager.getInstance(context, db); - applicationKeyStorage = ApplicationKeyStorage.getInstance(keystore); + applicationKeyStorage = ApplicationKeyStorage.getInstance(); } catch (NoSuchAlgorithmException e) { // Impossible: all algorithms must be supported by AOSP throw new RuntimeException(e); diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java index 84ddbf778c70..2398f56f847c 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java @@ -21,9 +21,13 @@ import static android.security.keystore.recovery.RecoveryController.ERROR_SERVIC import android.annotation.Nullable; import android.os.ServiceSpecificException; import android.security.Credentials; +import android.security.KeyStore; +import android.security.KeyStore2; import android.security.keystore.KeyProperties; import android.security.keystore.KeyProtection; -import android.security.KeyStore; +import android.system.keystore2.Domain; +import android.system.keystore2.KeyDescriptor; +import android.system.keystore2.KeyPermission; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -47,32 +51,37 @@ public class ApplicationKeyStorage { private static final String APPLICATION_KEY_ALIAS_PREFIX = "com.android.server.locksettings.recoverablekeystore/application/"; + private static final String APPLICATION_KEY_GRANT_PREFIX = "recoverable_key:"; private final KeyStoreProxy mKeyStore; - private final KeyStore mKeystoreService; - public static ApplicationKeyStorage getInstance(KeyStore keystoreService) + /** + * Creates a new instance. + */ + public static ApplicationKeyStorage getInstance() throws KeyStoreException { return new ApplicationKeyStorage( - new KeyStoreProxyImpl(KeyStoreProxyImpl.getAndLoadAndroidKeyStore()), - keystoreService); + new KeyStoreProxyImpl(KeyStoreProxyImpl.getAndLoadAndroidKeyStore())); } @VisibleForTesting - ApplicationKeyStorage(KeyStoreProxy keyStore, KeyStore keystoreService) { + ApplicationKeyStorage(KeyStoreProxy keyStore) { mKeyStore = keyStore; - mKeystoreService = keystoreService; } /** - * Returns grant alias, valid in Applications namespace. + * Returns String representation of {@code KeyDescriptor} valid in application's namespace. */ public @Nullable String getGrantAlias(int userId, int uid, String alias) { - // Aliases used by {@link KeyStore} are different than used by public API. - // {@code USER_PRIVATE_KEY} prefix is used secret keys. Log.i(TAG, String.format(Locale.US, "Get %d/%d/%s", userId, uid, alias)); - String keystoreAlias = Credentials.USER_PRIVATE_KEY + getInternalAlias(userId, uid, alias); - return mKeystoreService.grant(keystoreAlias, uid); + String keystoreAlias = getInternalAlias(userId, uid, alias); + if (useKeyStore2()) { + return makeKeystoreEngineGrantString(uid, keystoreAlias); + } else { + // Aliases used by {@link KeyStore} are different than used by public API. + // {@code USER_PRIVATE_KEY} prefix is used secret keys. + return KeyStore.getInstance().grant(Credentials.USER_PRIVATE_KEY + keystoreAlias, uid); + } } public void setSymmetricKeyEntry(int userId, int uid, String alias, byte[] secretKey) @@ -117,4 +126,31 @@ public class ApplicationKeyStorage { private String getInternalAlias(int userId, int uid, String alias) { return APPLICATION_KEY_ALIAS_PREFIX + userId + "/" + uid + "/" + alias; } + + private String makeKeystoreEngineGrantString(int uid, String alias) { + if (alias == null) { + return null; + } + + KeyDescriptor key = new KeyDescriptor(); + key.domain = Domain.APP; + key.nspace = KeyProperties.NAMESPACE_APPLICATION; + key.alias = alias; + key.blob = null; + + int grantAccessVector = KeyPermission.USE | KeyPermission.GET_INFO | KeyPermission.DELETE; + + try { + key = KeyStore2.getInstance().grant(key, uid, grantAccessVector); + } catch (android.security.KeyStoreException e) { + Log.e(TAG, "Failed to get grant for KeyStore key.", e); + throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage()); + } + return String.format("%s%016X", APPLICATION_KEY_GRANT_PREFIX, key.nspace); + } + + private static boolean useKeyStore2() { + return android.security.keystore2.AndroidKeyStoreProvider.isInstalled(); + } + } diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index bce80696f72c..22ed781da92d 100644 --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java @@ -40,6 +40,7 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> implements private static final int VERSION_ADD_NETWORK_ID = 3; private static final int VERSION_ADD_METERED = 4; private static final int VERSION_ADD_DEFAULT_NETWORK = 5; + private static final int VERSION_ADD_OEM_MANAGED_NETWORK = 6; public NetworkIdentitySet() { } @@ -84,13 +85,20 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> implements defaultNetwork = true; } + final int oemNetCapabilities; + if (version >= VERSION_ADD_OEM_MANAGED_NETWORK) { + oemNetCapabilities = in.readInt(); + } else { + oemNetCapabilities = NetworkIdentity.OEM_NONE; + } + add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered, - defaultNetwork)); + defaultNetwork, oemNetCapabilities)); } } public void writeToStream(DataOutput out) throws IOException { - out.writeInt(VERSION_ADD_DEFAULT_NETWORK); + out.writeInt(VERSION_ADD_OEM_MANAGED_NETWORK); out.writeInt(size()); for (NetworkIdentity ident : this) { out.writeInt(ident.getType()); @@ -100,6 +108,7 @@ public class NetworkIdentitySet extends HashSet<NetworkIdentity> implements out.writeBoolean(ident.getRoaming()); out.writeBoolean(ident.getMetered()); out.writeBoolean(ident.getDefaultNetwork()); + out.writeInt(ident.getOemManaged()); } } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index b5c0f28d8ba2..46ad4573512e 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -52,6 +52,7 @@ import static android.net.INetd.FIREWALL_RULE_DENY; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkIdentity.OEM_NONE; import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.SNOOZE_NEVER; import static android.net.NetworkPolicy.WARNING_DISABLED; @@ -1383,7 +1384,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final String subscriberId = mSubIdToSubscriberId.valueAt(i); final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, - true); + true, OEM_NONE); + /* While OEM_NONE indicates "any non OEM managed network", OEM_NONE is meant to be a + * placeholder value here. The probeIdent is matched against a NetworkTemplate which + * should have its OEM managed value set to OEM_MANAGED_ALL, which will cause the + * template to match probeIdent without regard to OEM managed status. */ if (template.matches(probeIdent)) { return subId; } @@ -1613,7 +1618,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // find and update the mobile NetworkPolicy for this subscriber id boolean policyUpdated = false; final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE, - TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, true); + TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, true, + OEM_NONE); for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) { final NetworkTemplate template = mNetworkPolicy.keyAt(i); if (template.matches(probeIdent)) { @@ -1842,7 +1848,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, - true); + true, OEM_NONE); // Template is matched when subscriber id matches. if (template.matches(probeIdent)) { matchingSubIds.add(subId); @@ -2157,7 +2163,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private boolean ensureActiveMobilePolicyAL(int subId, String subscriberId) { // Poke around to see if we already have a policy final NetworkIdentity probeIdent = new NetworkIdentity(TYPE_MOBILE, - TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, true); + TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, null, false, true, true, + OEM_NONE); for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) { final NetworkTemplate template = mNetworkPolicy.keyAt(i); if (template.matches(probeIdent)) { diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 9706bcece924..5b9a11bc5a31 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1319,7 +1319,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(), ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(), ident.getRoaming(), true /* metered */, - true /* onDefaultNetwork */); + true /* onDefaultNetwork */, ident.getOemManaged()); findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent); findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent); } diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 4a2fb5da5e70..b39a6b4f4658 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -780,7 +780,8 @@ public class PackageDexOptimizer { return getOatDir(codePath).getAbsolutePath(); } - static File getOatDir(File codePath) { + /** Returns the oat dir for the given code path */ + public static File getOatDir(File codePath) { return new File(codePath, OAT_DIR_NAME); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index febbfbce9e6c..4896fd91fb6c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -355,6 +355,7 @@ import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.Settings.DatabaseVersion; import com.android.server.pm.Settings.VersionInfo; import com.android.server.pm.dex.ArtManagerService; +import com.android.server.pm.dex.ArtUtils; import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.DexoptOptions; import com.android.server.pm.dex.PackageDexUsage; @@ -5350,6 +5351,23 @@ public class PackageManagerService extends IPackageManager.Stub } @Override + public int getTargetSdkVersion(String packageName) { + synchronized (mLock) { + final AndroidPackage pkg = mPackages.get(packageName); + if (pkg == null) { + return -1; + } + + final PackageSetting ps = getPackageSetting(pkg.getPackageName()); + if (shouldFilterApplicationLocked(ps, Binder.getCallingUid(), + UserHandle.getCallingUserId())) { + return -1; + } + return pkg.getTargetSdkVersion(); + } + } + + @Override public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) { return getActivityInfoInternal(component, flags, Binder.getCallingUid(), userId); } @@ -20581,7 +20599,7 @@ public class PackageManagerService extends IPackageManager.Stub } final Intent intent = getHomeIntent(); final List<ResolveInfo> resolveInfos = queryIntentActivitiesInternal(intent, null, - PackageManager.GET_META_DATA, userId); + MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId); final ResolveInfo preferredResolveInfo = findPreferredActivityNotLocked( intent, null, 0, resolveInfos, 0, true, false, false, userId); final String packageName = preferredResolveInfo != null @@ -24025,15 +24043,13 @@ public class PackageManagerService extends IPackageManager.Stub } @Override - public int getTargetSdkVersionForPackage(String packageName) - throws RemoteException { - int callingUser = UserHandle.getUserId(Binder.getCallingUid()); - ApplicationInfo info = getApplicationInfo(packageName, 0, callingUser); - if (info == null) { - throw new RemoteException( - "Couldn't get ApplicationInfo for package " + packageName); + public int getTargetSdkVersionForPackage(String packageName) throws RemoteException { + int targetSdk = getTargetSdkVersion(packageName); + if (targetSdk != -1) { + return targetSdk; } - return info.targetSdkVersion; + + throw new RemoteException("Couldn't get targetSdkVersion for package " + packageName); } @Override @@ -25523,43 +25539,14 @@ public class PackageManagerService extends IPackageManager.Stub } } - private String getOatDir(AndroidPackage pkg, @NonNull PackageSetting pkgSetting) { - if (!AndroidPackageUtils.canHaveOatDir(pkg, - pkgSetting.getPkgState().isUpdatedSystemApp())) { - return null; - } - File codePath = new File(pkg.getCodePath()); - if (codePath.isDirectory()) { - return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath(); - } - return null; - } - void deleteOatArtifactsOfPackage(String packageName) { - final String[] instructionSets; - final List<String> codePaths; - final String oatDir; final AndroidPackage pkg; final PackageSetting pkgSetting; synchronized (mLock) { pkg = mPackages.get(packageName); pkgSetting = mSettings.getPackageLPr(packageName); } - instructionSets = getAppDexInstructionSets( - AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting), - AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting)); - codePaths = AndroidPackageUtils.getAllCodePaths(pkg); - oatDir = getOatDir(pkg, pkgSetting); - - for (String codePath : codePaths) { - for (String isa : instructionSets) { - try { - mInstaller.deleteOdex(codePath, isa, oatDir); - } catch (InstallerException e) { - Log.e(TAG, "Failed deleting oat files for " + codePath, e); - } - } - } + mDexManager.deleteOptimizedFiles(ArtUtils.createArtPackageInfo(pkg, pkgSetting)); } Set<String> getUnusedPackages(long downgradeTimeThresholdMillis) { diff --git a/services/core/java/com/android/server/pm/dex/ArtPackageInfo.java b/services/core/java/com/android/server/pm/dex/ArtPackageInfo.java new file mode 100644 index 000000000000..50bf916dceb3 --- /dev/null +++ b/services/core/java/com/android/server/pm/dex/ArtPackageInfo.java @@ -0,0 +1,58 @@ +/* + * 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.pm.dex; + +import java.util.List; + +/** + * Holds package information relevant to ART use cases. + */ +public class ArtPackageInfo { + private final String mPackageName; + private final List<String> mInstructionSets; + private final List<String> mCodePaths; + // TODO: This should be computed on the fly in PackageDexOptimizer / DexManager, but the + // logic is too complicated to do it in a single re-factoring. + private final String mOatDir; + + public ArtPackageInfo( + String packageName, + List<String> instructionSets, + List<String> codePaths, + String oatDir) { + mPackageName = packageName; + mInstructionSets = instructionSets; + mCodePaths = codePaths; + mOatDir = oatDir; + } + + public String getPackageName() { + return mPackageName; + } + + public List<String> getInstructionSets() { + return mInstructionSets; + } + + public List<String> getCodePaths() { + return mCodePaths; + } + + public String getOatDir() { + return mOatDir; + } +} diff --git a/services/core/java/com/android/server/pm/dex/ArtUtils.java b/services/core/java/com/android/server/pm/dex/ArtUtils.java new file mode 100644 index 000000000000..fe6ec0d37ca1 --- /dev/null +++ b/services/core/java/com/android/server/pm/dex/ArtUtils.java @@ -0,0 +1,64 @@ +/* + * 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.pm.dex; + +import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; + +import android.annotation.NonNull; + +import com.android.server.pm.PackageDexOptimizer; +import com.android.server.pm.PackageSetting; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.AndroidPackageUtils; + +import java.io.File; +import java.util.Arrays; + +/** + * Utility class to interface between PM and ART tooling (e.g. DexManager). + */ +public final class ArtUtils { + private ArtUtils() { + } + + /** + * Create the ART-representation of package info. + */ + public static ArtPackageInfo createArtPackageInfo( + AndroidPackage pkg, PackageSetting pkgSetting) { + return new ArtPackageInfo( + pkg.getPackageName(), + Arrays.asList(getAppDexInstructionSets( + AndroidPackageUtils.getPrimaryCpuAbi(pkg, pkgSetting), + AndroidPackageUtils.getSecondaryCpuAbi(pkg, pkgSetting))), + AndroidPackageUtils.getAllCodePaths(pkg), + getOatDir(pkg, pkgSetting)); + } + + private static String getOatDir(AndroidPackage pkg, @NonNull PackageSetting pkgSetting) { + if (!AndroidPackageUtils.canHaveOatDir(pkg, + pkgSetting.getPkgState().isUpdatedSystemApp())) { + return null; + } + File codePath = new File(pkg.getCodePath()); + if (codePath.isDirectory()) { + return PackageDexOptimizer.getOatDir(codePath).getAbsolutePath(); + } + return null; + } + +} diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index 6d3de968b036..349561d3f1d1 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -1015,6 +1015,22 @@ public class DexManager { return isBtmCritical; } + /** + * Deletes all the optimizations files generated by ART. + * @param packageInfo the package information. + */ + public void deleteOptimizedFiles(ArtPackageInfo packageInfo) { + for (String codePath : packageInfo.getCodePaths()) { + for (String isa : packageInfo.getInstructionSets()) { + try { + mInstaller.deleteOdex(codePath, isa, packageInfo.getOatDir()); + } catch (InstallerException e) { + Log.e(TAG, "Failed deleting oat files for " + codePath, e); + } + } + } + } + public static class RegisterDexModuleResult { public RegisterDexModuleResult() { this(false, null); diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java index 09b4f8967729..64fa70812528 100644 --- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java +++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java @@ -399,7 +399,8 @@ public class PackageInfoUtils { ParsedProcess proc = procs.get(key); retProcs.put(proc.getName(), new ProcessInfo(proc.getName(), new ArraySet<>(proc.getDeniedPermissions()), - proc.getGwpAsanMode())); + proc.getGwpAsanMode(), proc.getMemtagMode(), + proc.getNativeHeapZeroInit())); } return retProcs; } diff --git a/services/core/java/com/android/server/pm/verify/domain/OWNERS b/services/core/java/com/android/server/pm/verify/domain/OWNERS new file mode 100644 index 000000000000..c669112e0512 --- /dev/null +++ b/services/core/java/com/android/server/pm/verify/domain/OWNERS @@ -0,0 +1,5 @@ +# Bug component: 36137 + +chiuwinson@google.com +patb@google.com +toddke@google.com
\ No newline at end of file diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 9caef13acc8e..032e14959ef8 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -309,6 +309,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -318,6 +319,9 @@ import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.Constructor; import java.nio.charset.StandardCharsets; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; import java.text.DateFormat; import java.time.LocalDate; import java.util.ArrayList; @@ -6487,7 +6491,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, DELEGATION_CERT_INSTALL); } - final KeyGenParameterSpec keySpec = parcelableKeySpec.getSpec(); + KeyGenParameterSpec keySpec = parcelableKeySpec.getSpec(); final String alias = keySpec.getKeystoreAlias(); if (TextUtils.isEmpty(alias)) { throw new IllegalArgumentException("Empty alias provided."); @@ -6499,9 +6503,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return false; } - if (deviceIdAttestationRequired && (keySpec.getAttestationChallenge() == null)) { - throw new IllegalArgumentException( - "Requested Device ID attestation but challenge is empty."); + if (deviceIdAttestationRequired) { + if (keySpec.getAttestationChallenge() == null) { + throw new IllegalArgumentException( + "Requested Device ID attestation but challenge is empty."); + } + KeyGenParameterSpec.Builder specBuilder = new KeyGenParameterSpec.Builder(keySpec); + specBuilder.setAttestationIds(attestationUtilsFlags); + specBuilder.setDevicePropertiesAttestationIncluded(true); + keySpec = specBuilder.build(); } final UserHandle userHandle = mInjector.binderGetCallingUserHandle(); @@ -6511,15 +6521,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { KeyChain.bindAsUser(mContext, userHandle)) { IKeyChainService keyChain = keyChainConnection.getService(); - // Copy the provided keySpec, excluding the attestation challenge, which will be - // used later for requesting key attestation record. - final KeyGenParameterSpec noAttestationSpec = - new KeyGenParameterSpec.Builder(keySpec) - .setAttestationChallenge(null) - .build(); - final int generationResult = keyChain.generateKeyPair(algorithm, - new ParcelableKeyGenParameterSpec(noAttestationSpec)); + new ParcelableKeyGenParameterSpec(keySpec)); if (generationResult != KeyChain.KEY_GEN_SUCCESS) { Log.e(LOG_TAG, String.format( "KeyChain failed to generate a keypair, error %d.", generationResult)); @@ -6528,6 +6531,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { throw new ServiceSpecificException( DevicePolicyManager.KEY_GEN_STRONGBOX_UNAVAILABLE, String.format("KeyChain error: %d", generationResult)); + case KeyChain.KEY_ATTESTATION_CANNOT_ATTEST_IDS: + throw new UnsupportedOperationException( + "Device does not support Device ID attestation."); default: return false; } @@ -6540,22 +6546,26 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { // that UID. keyChain.setGrant(callingUid, alias, true); - final byte[] attestationChallenge = keySpec.getAttestationChallenge(); - if (attestationChallenge != null) { - final int attestationResult = keyChain.attestKey( - alias, attestationChallenge, attestationUtilsFlags, attestationChain); - if (attestationResult != KeyChain.KEY_ATTESTATION_SUCCESS) { - Log.e(LOG_TAG, String.format( - "Attestation for %s failed (rc=%d), deleting key.", - alias, attestationResult)); - keyChain.removeKeyPair(alias); - if (attestationResult == KeyChain.KEY_ATTESTATION_CANNOT_ATTEST_IDS) { - throw new UnsupportedOperationException( - "Device does not support Device ID attestation."); + try { + final List<byte[]> encodedCerts = new ArrayList(); + final CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + final byte[] certChainBytes = keyChain.getCaCertificates(alias); + encodedCerts.add(keyChain.getCertificate(alias)); + if (certChainBytes != null) { + final Collection<X509Certificate> certs = + (Collection<X509Certificate>) certFactory.generateCertificates( + new ByteArrayInputStream(certChainBytes)); + for (X509Certificate cert : certs) { + encodedCerts.add(cert.getEncoded()); } - return false; } + + attestationChain.shallowCopyFrom(new KeymasterCertificateChain(encodedCerts)); + } catch (CertificateException e) { + Log.e(LOG_TAG, "While retrieving certificate chain.", e); + return false; } + final boolean isDelegate = (who == null); DevicePolicyEventLogger .createEvent(DevicePolicyEnums.GENERATE_KEY_PAIR) diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java index 7f86faa4b393..d4e4caa906a1 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java @@ -19,6 +19,7 @@ package com.android.server.job.controllers; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -626,6 +627,7 @@ public class ConnectivityControllerTest { private static NetworkCapabilities createCapabilities() { return new NetworkCapabilities().addCapability(NET_CAPABILITY_INTERNET) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) .addCapability(NET_CAPABILITY_VALIDATED); } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java index 4e1454bd0962..1db5fcc70420 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java @@ -150,7 +150,7 @@ public class LockSettingsServiceTestable extends LockSettingsService { } @Override - public RecoverableKeyStoreManager getRecoverableKeyStoreManager(KeyStore keyStore) { + public RecoverableKeyStoreManager getRecoverableKeyStoreManager() { return mRecoverableKeyStoreManager; } diff --git a/services/tests/servicestests/src/com/android/server/pm/OWNERS b/services/tests/servicestests/src/com/android/server/pm/OWNERS index d825dfd7cf00..e15b5f57069c 100644 --- a/services/tests/servicestests/src/com/android/server/pm/OWNERS +++ b/services/tests/servicestests/src/com/android/server/pm/OWNERS @@ -1 +1,3 @@ include /services/core/java/com/android/server/pm/OWNERS + +per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS diff --git a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS index 816bc6bba639..e21b66ecb394 100644 --- a/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS +++ b/services/tests/servicestests/src/com/android/server/soundtrigger_middleware/OWNERS @@ -1 +1 @@ -include /core/java/android/media/soundtrigger/OWNERS +include /media/java/android/media/soundtrigger_middleware/OWNERS diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 9861973bcae8..04e8f6345dee 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -4157,6 +4157,21 @@ public class CarrierConfigManager { public static final String KEY_ALLOWED_INITIAL_ATTACH_APN_TYPES_STRING_ARRAY = "allowed_initial_attach_apn_types_string_array"; + /** + * Boolean indicating whether the SIM PIN can be stored and verified + * seamlessly after an unattended reboot. + * + * The device configuration value {@code config_allow_pin_storage_for_unattended_reboot} + * ultimately controls whether this carrier configuration option is used. Where + * {@code config_allow_pin_storage_for_unattended_reboot} is false, the value of the + * {@link #KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL} carrier configuration option is + * ignored. + * + * @hide + */ + public static final String KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL = + "store_sim_pin_for_unattended_reboot_bool"; + /** The default value for every variable. */ private final static PersistableBundle sDefaults; @@ -4710,6 +4725,7 @@ public class CarrierConfigManager { sDefaults.putInt(KEY_DEFAULT_RTT_MODE_INT, 0); sDefaults.putStringArray(KEY_ALLOWED_INITIAL_ATTACH_APN_TYPES_STRING_ARRAY, new String[]{"ia", "default", "ims", "mms", "dun", "emergency"}); + sDefaults.putBoolean(KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL, true); } /** diff --git a/telephony/java/android/telephony/RadioInterfaceCapabilities.java b/telephony/java/android/telephony/RadioInterfaceCapabilities.java deleted file mode 100644 index 7c7eb9fbbeb2..000000000000 --- a/telephony/java/android/telephony/RadioInterfaceCapabilities.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.telephony; - -import android.util.ArraySet; - -/** - * Contains the set of supported capabilities that the Radio Interface supports on this device. - * - * @hide - */ -public class RadioInterfaceCapabilities { - - private final ArraySet<String> mSupportedCapabilities; - - - public RadioInterfaceCapabilities() { - mSupportedCapabilities = new ArraySet<>(); - } - - /** - * Marks a capability as supported - * - * @param capabilityName the name of the capability - */ - public void addSupportedCapability( - @TelephonyManager.RadioInterfaceCapability String capabilityName) { - mSupportedCapabilities.add(capabilityName); - } - - /** - * Whether the capability is supported - * - * @param capabilityName the name of the capability - */ - public boolean isSupported(String capabilityName) { - return mSupportedCapabilities.contains(capabilityName); - } -} diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java index af67ed279fab..fe7e5976b132 100644 --- a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java +++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java @@ -187,7 +187,7 @@ public final class SignalStrengthUpdateRequest implements Parcelable { return mIsSystemThresholdReportingRequestedWhileIdle; } - /* + /** * @return the live token of the request * * @hide diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index e8ace34793db..403d1d01903c 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -28,6 +28,7 @@ import android.annotation.IntDef; import android.annotation.LongDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -121,12 +122,10 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.UUID; import java.util.concurrent.Executor; import java.util.function.Consumer; @@ -8127,6 +8126,11 @@ public class TelephonyManager { * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling * app has carrier privileges (see {@link #hasCarrierPrivileges}). + * <p> + * If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported} + * ({@link TelephonyManager#CAPABILITY_ALLOWED_NETWORK_TYPES_USED}) returns true, then + * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise, + * setPreferredNetworkTypesBitmap is used instead. * * @param subId the id of the subscription to set the preferred network type for. * @param networkType the preferred network type @@ -8158,6 +8162,11 @@ public class TelephonyManager { * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling * app has carrier privileges (see {@link #hasCarrierPrivileges}). + * <p> + * If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported} + * ({@link TelephonyManager#CAPABILITY_ALLOWED_NETWORK_TYPES_USED}) returns true, then + * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise, + * setPreferredNetworkTypesBitmap is used instead. * * @param networkTypeBitmask The bitmask of preferred network types. * @return true on success; false on any failure. @@ -8183,12 +8192,20 @@ public class TelephonyManager { * Set the allowed network types of the device. This is for carrier or privileged apps to * enable/disable certain network types on the device. The user preferred network types should * be set through {@link #setPreferredNetworkTypeBitmask}. + * <p> + * If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported} + * ({@link TelephonyManager#CAPABILITY_ALLOWED_NETWORK_TYPES_USED}) returns true, then + * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise, + * setPreferredNetworkTypesBitmap is used instead. * * @param allowedNetworkTypes The bitmask of allowed network types. * @return true on success; false on any failure. * @hide */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature( + enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported", + value = TelephonyManager.CAPABILITY_ALLOWED_NETWORK_TYPES_USED) @SystemApi public boolean setAllowedNetworkTypes(@NetworkTypeBitMask long allowedNetworkTypes) { try { @@ -8227,12 +8244,12 @@ public class TelephonyManager { * {@link #ALLOWED_NETWORK_TYPES_REASON_POWER} * </ol> * This API will result in allowing an intersection of allowed network types for all reasons, - * including the configuration done through {@link setAllowedNetworkTypes}. - * While this API and {@link setAllowedNetworkTypes} is controlling allowed network types - * on device, user preference will still be set through {@link #setPreferredNetworkTypeBitmask}. - * Thus resultant network type configured on modem will be an intersection of the network types - * from setAllowedNetworkTypesForReason, {@link setAllowedNetworkTypes} - * and {@link #setPreferredNetworkTypeBitmask}. + * including the configuration done through other reasons. + * <p> + * If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported} + * ({@link TelephonyManager#CAPABILITY_ALLOWED_NETWORK_TYPES_USED}) returns true, then + * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise, + * setPreferredNetworkTypesBitmap is used instead. * * @param reason the reason the allowed network type change is taking place * @param allowedNetworkTypes The bitmask of allowed network types. @@ -8241,6 +8258,9 @@ public class TelephonyManager { * @hide */ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresFeature( + enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported", + value = TelephonyManager.CAPABILITY_ALLOWED_NETWORK_TYPES_USED) public void setAllowedNetworkTypesForReason(@AllowedNetworkTypesReason int reason, @NetworkTypeBitMask long allowedNetworkTypes) { if (reason != ALLOWED_NETWORK_TYPES_REASON_POWER) { @@ -8278,6 +8298,9 @@ public class TelephonyManager { * @hide */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresFeature( + enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported", + value = TelephonyManager.CAPABILITY_ALLOWED_NETWORK_TYPES_USED) public @NetworkTypeBitMask long getAllowedNetworkTypesForReason( @AllowedNetworkTypesReason int reason) { if (reason != ALLOWED_NETWORK_TYPES_REASON_POWER) { @@ -14356,10 +14379,24 @@ public class TelephonyManager { public static final String CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE = "CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE"; + /** + * Indicates whether {@link #setPreferredNetworkType}, {@link + * #setPreferredNetworkTypeBitmask}, {@link #setAllowedNetworkTypes} and + * {@link #setAllowedNetworkTypesForReason} rely on + * setAllowedNetworkTypesBitmap instead of setPreferredNetworkTypesBitmap on the radio + * interface. + * + * @hide + */ + @SystemApi + public static final String CAPABILITY_ALLOWED_NETWORK_TYPES_USED = + "CAPABILITY_ALLOWED_NETWORK_TYPES_USED"; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @StringDef(prefix = "CAPABILITY_", value = { CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE, + CAPABILITY_ALLOWED_NETWORK_TYPES_USED, }) public @interface RadioInterfaceCapability {} @@ -14824,4 +14861,66 @@ public class TelephonyManager { Log.e(TAG, "Error calling ITelephony#clearSignalStrengthUpdateRequest", e); } } + + /** + * The unattended reboot was prepared successfully. + * @hide + */ + @SystemApi + public static final int PREPARE_UNATTENDED_REBOOT_SUCCESS = 0; + + /** + * The unattended reboot was prepared, but the user will need to manually + * enter the PIN code of at least one SIM card present in the device. + * @hide + */ + @SystemApi + public static final int PREPARE_UNATTENDED_REBOOT_PIN_REQUIRED = 1; + + /** + * The unattended reboot was not prepared due to generic error. + * @hide + */ + @SystemApi + public static final int PREPARE_UNATTENDED_REBOOT_ERROR = 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"PREPARE_UNATTENDED_REBOOT_"}, + value = { + PREPARE_UNATTENDED_REBOOT_SUCCESS, + PREPARE_UNATTENDED_REBOOT_PIN_REQUIRED, + PREPARE_UNATTENDED_REBOOT_ERROR + }) + public @interface PrepareUnattendedRebootResult {} + + /** + * Prepare TelephonyManager for an unattended reboot. The reboot is required to be done + * shortly (e.g. within 15 seconds) after the API is invoked. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#REBOOT} + * + * @return {@link #PREPARE_UNATTENDED_REBOOT_SUCCESS} in case of success. + * {@link #PREPARE_UNATTENDED_REBOOT_PIN_REQUIRED} if the device contains + * at least one SIM card for which the user needs to manually enter the PIN + * code after the reboot. {@link #PREPARE_UNATTENDED_REBOOT_ERROR} in case + * of error. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.REBOOT) + @PrepareUnattendedRebootResult + public int prepareForUnattendedReboot() { + try { + ITelephony service = getITelephony(); + if (service != null) { + return service.prepareForUnattendedReboot(); + } + } catch (RemoteException e) { + Log.e(TAG, "Telephony#prepareForUnattendedReboot RemoteException", e); + e.rethrowFromSystemServer(); + } + return PREPARE_UNATTENDED_REBOOT_ERROR; + } } diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java index 070fd799d6cc..ce8bd7d8c28e 100644 --- a/telephony/java/android/telephony/ims/RcsUceAdapter.java +++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java @@ -467,7 +467,7 @@ public class RcsUceAdapter { * poll on the network unless there are contacts being queried with stale information. * <p> * Be sure to check the availability of this feature using - * {@link ImsRcsManager#isAvailable(int)} and ensuring + * {@link ImsRcsManager#isAvailable(int, int)} and ensuring * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} or * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} is enabled or else * this operation will fail with {@link #ERROR_NOT_AVAILABLE} or {@link #ERROR_NOT_ENABLED}. @@ -484,7 +484,8 @@ public class RcsUceAdapter { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresPermission(allOf = {Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, + Manifest.permission.READ_CONTACTS}) public void requestCapabilities(@NonNull List<Uri> contactNumbers, @NonNull @CallbackExecutor Executor executor, @NonNull CapabilitiesCallback c) throws ImsException { @@ -557,7 +558,7 @@ public class RcsUceAdapter { * * <p> * Be sure to check the availability of this feature using - * {@link ImsRcsManager#isAvailable(int)} and ensuring + * {@link ImsRcsManager#isAvailable(int, int)} and ensuring * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_OPTIONS_UCE} or * {@link RcsFeature.RcsImsCapabilities#CAPABILITY_TYPE_PRESENCE_UCE} is * enabled or else this operation will fail with @@ -571,7 +572,8 @@ public class RcsUceAdapter { * @hide */ @SystemApi - @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @RequiresPermission(allOf = {Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, + Manifest.permission.READ_CONTACTS}) public void requestAvailability(@NonNull Uri contactNumber, @NonNull @CallbackExecutor Executor executor, @NonNull CapabilitiesCallback c) throws ImsException { diff --git a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java index 4967e5da7c9a..62955487897f 100644 --- a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java +++ b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java @@ -25,7 +25,6 @@ import android.telephony.ims.RcsContactUceCapability; import android.telephony.ims.RcsUceAdapter; import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.feature.RcsFeature; -import android.util.Log; import java.util.List; @@ -44,30 +43,12 @@ public interface CapabilityExchangeEventListener { * Respond to a remote capability request from the contact specified with the * capabilities of this device. * @param ownCapabilities The capabilities of this device. - * @hide - */ - default void onRespondToCapabilityRequest( - @NonNull RcsContactUceCapability ownCapabilities) {} - - /** - * Respond to a remote capability request from the contact specified with the - * capabilities of this device. - * @param ownCapabilities The capabilities of this device. * @param isBlocked Whether or not the user has blocked the number requesting the * capabilities of this device. If true, the device should respond to the OPTIONS * request with a 200 OK response and no capabilities. */ - default void onRespondToCapabilityRequest(@NonNull RcsContactUceCapability ownCapabilities, - boolean isBlocked) { - Log.w("CapabilityExchangeEventListener", "implement " - + "onRespondToCapabilityRequest(RcsContactUceCapability, boolean) instead!"); - // Fall back to old implementation - if (isBlocked) { - onRespondToCapabilityRequestWithError(200, "OK"); - } else { - onRespondToCapabilityRequest(ownCapabilities); - } - } + void onRespondToCapabilityRequest(@NonNull RcsContactUceCapability ownCapabilities, + boolean isBlocked); /** * Respond to a remote capability request from the contact specified with the diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 77d46f4c39cd..e270b8dc3fe4 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -2414,4 +2414,18 @@ interface ITelephony { */ void clearSignalStrengthUpdateRequest(int subId, in SignalStrengthUpdateRequest request, String callingPackage); + + /** + * Prepare TelephonyManager for an unattended reboot. The reboot is + * required to be done shortly after the API is invoked. + * + * Requires system privileges. + * + * @return {@link #PREPARE_UNATTENDED_REBOOT_SUCCESS} in case of success. + * {@link #PREPARE_UNATTENDED_REBOOT_PIN_REQUIRED} if the device contains + * at least one SIM card for which the user needs to manually enter the PIN + * code after the reboot. {@link #PREPARE_UNATTENDED_REBOOT_ERROR} in case + * of error. + */ + int prepareForUnattendedReboot(); } diff --git a/test-base/Android.bp b/test-base/Android.bp index 0b7a3981a403..9bd639b63ae0 100644 --- a/test-base/Android.bp +++ b/test-base/Android.bp @@ -49,6 +49,12 @@ java_sdk_library { compile_dex: true, default_to_stubs: true, + + // Additional hiddenapi annotations are provided in a separate module. + // TODO(b/180295980) - investigate whether this can be removed + hiddenapi_additional_annotations: [ + "android.test.base-hiddenapi-annotations", + ], } // Build the android.test.base_static library @@ -91,8 +97,9 @@ java_library_static { // =============================================== // This contains the android.test classes from android.test.base plus // the com.android.internal.util.Predicate[s] classes. This is only -// intended for inclusion in android.test.legacy and must not be used -// elsewhere. +// intended for inclusion in android.test.legacy and in +// android.test.base-hiddenapi-annotations to avoid a dependency cycle and must +// not be used elsewhere. java_library_static { name: "android.test.base-minus-junit", diff --git a/test-base/hiddenapi/Android.bp b/test-base/hiddenapi/Android.bp index d4f52d0fc6cd..1466590ef311 100644 --- a/test-base/hiddenapi/Android.bp +++ b/test-base/hiddenapi/Android.bp @@ -14,11 +14,6 @@ // limitations under the License. // -// Provided solely to contribute information about which hidden parts of the android.test.base -// library are used by apps. The source files are stubs of the actual files in ../src which use the -// UnsupportedAppUsage annotation to tag those methods that are accessible via the hiddenapi. -// Relies on the convention that modules with name <x>-hiddenapi provide hiddenapi information for -// module <x> that is on the bootclasspath. package { // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import @@ -28,14 +23,20 @@ package { default_applicable_licenses: ["frameworks_base_license"], } +// Provided solely to contribute information about which hidden parts of the android.test.base +// library are used by apps. The source files are stubs of the actual files in ../src which use the +// UnsupportedAppUsage annotation to tag those methods that are accessible via the hiddenapi. java_library { - name: "android.test.base-hiddenapi", + name: "android.test.base-hiddenapi-annotations", compile_dex: true, srcs: ["src/**/*.java"], libs: [ - "android.test.base", + // Use this instead of `android.test.base` to avoid a dependency cycle + // as `android.test.base` depends on this. + "android.test.base-minus-junit", + "junit", "unsupportedappusage", ], } diff --git a/tests/net/common/java/android/net/CaptivePortalDataTest.kt b/tests/net/common/java/android/net/CaptivePortalDataTest.kt index ad5bbf220d57..18a93319b271 100644 --- a/tests/net/common/java/android/net/CaptivePortalDataTest.kt +++ b/tests/net/common/java/android/net/CaptivePortalDataTest.kt @@ -55,14 +55,14 @@ class CaptivePortalDataTest { .build() private val dataFromPasspoint = CaptivePortalData.Builder() - .setUserPortalUrl(Uri.parse("https://tc.example.com/passpoint"), - CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) - .setVenueInfoUrl(Uri.parse("https://venue.example.com/passpoint"), - CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) .setCaptive(true) .apply { if (SdkLevel.isAtLeastS()) { setVenueFriendlyName("venue friendly name") + setUserPortalUrl(Uri.parse("https://tc.example.com/passpoint"), + CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) + setVenueInfoUrl(Uri.parse("https://venue.example.com/passpoint"), + CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) } } .build() @@ -96,28 +96,28 @@ class CaptivePortalDataTest { if (SdkLevel.isAtLeastS()) { assertNotEqualsAfterChange { it.setVenueFriendlyName("another friendly name") } assertNotEqualsAfterChange { it.setVenueFriendlyName(null) } - } - assertEquals(dataFromPasspoint, CaptivePortalData.Builder(dataFromPasspoint).build()) - assertNotEqualsAfterChange { it.setUserPortalUrl( - Uri.parse("https://tc.example.com/passpoint")) } - assertNotEqualsAfterChange { it.setUserPortalUrl( - Uri.parse("https://tc.example.com/passpoint"), - CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) } - assertNotEqualsAfterChange { it.setUserPortalUrl( - Uri.parse("https://tc.example.com/other"), - CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) } - assertNotEqualsAfterChange { it.setUserPortalUrl( - Uri.parse("https://tc.example.com/passpoint"), - CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) } - assertNotEqualsAfterChange { it.setVenueInfoUrl( - Uri.parse("https://venue.example.com/passpoint")) } - assertNotEqualsAfterChange { it.setVenueInfoUrl( - Uri.parse("https://venue.example.com/other"), - CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) } - assertNotEqualsAfterChange { it.setVenueInfoUrl( - Uri.parse("https://venue.example.com/passpoint"), - CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) } + assertEquals(dataFromPasspoint, CaptivePortalData.Builder(dataFromPasspoint).build()) + assertNotEqualsAfterChange { it.setUserPortalUrl( + Uri.parse("https://tc.example.com/passpoint")) } + assertNotEqualsAfterChange { it.setUserPortalUrl( + Uri.parse("https://tc.example.com/passpoint"), + CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) } + assertNotEqualsAfterChange { it.setUserPortalUrl( + Uri.parse("https://tc.example.com/other"), + CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) } + assertNotEqualsAfterChange { it.setUserPortalUrl( + Uri.parse("https://tc.example.com/passpoint"), + CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) } + assertNotEqualsAfterChange { it.setVenueInfoUrl( + Uri.parse("https://venue.example.com/passpoint")) } + assertNotEqualsAfterChange { it.setVenueInfoUrl( + Uri.parse("https://venue.example.com/other"), + CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) } + assertNotEqualsAfterChange { it.setVenueInfoUrl( + Uri.parse("https://venue.example.com/passpoint"), + CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) } + } } @Test diff --git a/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt b/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt new file mode 100644 index 000000000000..56b56efd501b --- /dev/null +++ b/tests/net/common/java/android/net/NetworkStateSnapshotTest.kt @@ -0,0 +1,73 @@ +/* + * 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.net + +import android.net.ConnectivityManager.TYPE_NONE +import android.net.ConnectivityManager.TYPE_WIFI +import android.net.InetAddresses.parseNumericAddress +import android.net.NetworkCapabilities.TRANSPORT_WIFI +import android.os.Build +import androidx.test.filters.SmallTest +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRunner +import com.android.testutils.assertParcelSane +import org.junit.Test +import org.junit.runner.RunWith +import java.net.Inet4Address +import java.net.Inet6Address + +private const val TEST_IMSI = "imsi1" +private const val TEST_SSID = "SSID1" +private const val TEST_NETID = 123 + +private val TEST_IPV4_GATEWAY = parseNumericAddress("192.168.222.3") as Inet4Address +private val TEST_IPV6_GATEWAY = parseNumericAddress("2001:db8::1") as Inet6Address +private val TEST_IPV4_LINKADDR = LinkAddress("192.168.222.123/24") +private val TEST_IPV6_LINKADDR = LinkAddress("2001:db8::123/64") +private val TEST_IFACE = "fake0" +private val TEST_LINK_PROPERTIES = LinkProperties().apply { + interfaceName = TEST_IFACE + addLinkAddress(TEST_IPV4_LINKADDR) + addLinkAddress(TEST_IPV6_LINKADDR) + + // Add default routes + addRoute(RouteInfo(IpPrefix(parseNumericAddress("0.0.0.0"), 0), TEST_IPV4_GATEWAY)) + addRoute(RouteInfo(IpPrefix(parseNumericAddress("::"), 0), TEST_IPV6_GATEWAY)) +} + +private val TEST_CAPABILITIES = NetworkCapabilities().apply { + addTransportType(TRANSPORT_WIFI) + setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false) + setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true) + setSSID(TEST_SSID) +} + +@SmallTest +@RunWith(DevSdkIgnoreRunner::class) +@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) +class NetworkStateSnapshotTest { + + @Test + fun testParcelUnparcel() { + val emptySnapshot = NetworkStateSnapshot(LinkProperties(), NetworkCapabilities(), + Network(TEST_NETID), null, TYPE_NONE) + val snapshot = NetworkStateSnapshot( + TEST_LINK_PROPERTIES, TEST_CAPABILITIES, Network(TEST_NETID), TEST_IMSI, TYPE_WIFI) + assertParcelSane(emptySnapshot, 5) + assertParcelSane(snapshot, 5) + } +} diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java index dc9e587332cb..e1da3d0ae2b3 100644 --- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java +++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java @@ -17,6 +17,7 @@ package com.android.server; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; @@ -84,6 +85,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { final String typeName = ConnectivityManager.getNetworkTypeName(type); mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities(); mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED); + mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); mNetworkCapabilities.addTransportType(transport); switch (transport) { case TRANSPORT_ETHERNET: diff --git a/tests/net/java/android/net/NetworkIdentityTest.kt b/tests/net/java/android/net/NetworkIdentityTest.kt new file mode 100644 index 000000000000..eb2b85c14578 --- /dev/null +++ b/tests/net/java/android/net/NetworkIdentityTest.kt @@ -0,0 +1,54 @@ +/* + * 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.net + +import android.net.NetworkIdentity.OEM_NONE +import android.net.NetworkIdentity.OEM_PAID +import android.net.NetworkIdentity.OEM_PRIVATE +import android.net.NetworkIdentity.getOemBitfield +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import kotlin.test.assertEquals + +@RunWith(JUnit4::class) +class NetworkIdentityTest { + @Test + fun testGetOemBitfield() { + val oemNone = NetworkCapabilities().apply { + setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, false) + setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, false) + } + val oemPaid = NetworkCapabilities().apply { + setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, true) + setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, false) + } + val oemPrivate = NetworkCapabilities().apply { + setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, false) + setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, true) + } + val oemAll = NetworkCapabilities().apply { + setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, true) + setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, true) + } + + assertEquals(getOemBitfield(oemNone), OEM_NONE) + assertEquals(getOemBitfield(oemPaid), OEM_PAID) + assertEquals(getOemBitfield(oemPrivate), OEM_PRIVATE) + assertEquals(getOemBitfield(oemAll), OEM_PAID or OEM_PRIVATE) + } +} diff --git a/tests/net/java/android/net/NetworkTemplateTest.kt b/tests/net/java/android/net/NetworkTemplateTest.kt index b39555d15dcb..27224c216db3 100644 --- a/tests/net/java/android/net/NetworkTemplateTest.kt +++ b/tests/net/java/android/net/NetworkTemplateTest.kt @@ -20,14 +20,23 @@ import android.content.Context import android.net.ConnectivityManager.TYPE_MOBILE import android.net.ConnectivityManager.TYPE_WIFI import android.net.NetworkIdentity.SUBTYPE_COMBINED +import android.net.NetworkIdentity.OEM_NONE; +import android.net.NetworkIdentity.OEM_PAID; +import android.net.NetworkIdentity.OEM_PRIVATE; import android.net.NetworkIdentity.buildNetworkIdentity import android.net.NetworkStats.DEFAULT_NETWORK_ALL import android.net.NetworkStats.METERED_ALL import android.net.NetworkStats.ROAMING_ALL +import android.net.NetworkTemplate.MATCH_ETHERNET import android.net.NetworkTemplate.MATCH_MOBILE +import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD import android.net.NetworkTemplate.MATCH_WIFI +import android.net.NetworkTemplate.MATCH_WIFI_WILDCARD import android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA import android.net.NetworkTemplate.NETWORK_TYPE_ALL +import android.net.NetworkTemplate.OEM_MANAGED_ALL +import android.net.NetworkTemplate.OEM_MANAGED_NO +import android.net.NetworkTemplate.OEM_MANAGED_YES import android.net.NetworkTemplate.buildTemplateMobileWithRatType import android.telephony.TelephonyManager import com.android.testutils.assertParcelSane @@ -37,9 +46,11 @@ import org.junit.runner.RunWith import org.junit.runners.JUnit4 import org.mockito.Mockito.mock import org.mockito.MockitoAnnotations +import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertNotEquals import kotlin.test.assertTrue +import kotlin.test.fail private const val TEST_IMSI1 = "imsi1" private const val TEST_IMSI2 = "imsi2" @@ -57,13 +68,18 @@ class NetworkTemplateTest { private fun buildNetworkState( type: Int, subscriberId: String? = null, - ssid: String? = null + ssid: String? = null, + oemManaged: Int = OEM_NONE, ): NetworkState { val lp = LinkProperties() val caps = NetworkCapabilities().apply { setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false) setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true) setSSID(ssid) + setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID, + (oemManaged and OEM_PAID) == OEM_PAID) + setCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, + (oemManaged and OEM_PRIVATE) == OEM_PRIVATE) } return NetworkState(type, lp, caps, mock(Network::class.java), subscriberId) } @@ -136,11 +152,15 @@ class NetworkTemplateTest { @Test fun testParcelUnparcel() { val templateMobile = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1, null, null, METERED_ALL, - ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE) + ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_LTE, + OEM_MANAGED_ALL) val templateWifi = NetworkTemplate(MATCH_WIFI, null, null, TEST_SSID1, METERED_ALL, - ROAMING_ALL, DEFAULT_NETWORK_ALL, 0) - assertParcelSane(templateMobile, 8) - assertParcelSane(templateWifi, 8) + ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_ALL) + val templateOem = NetworkTemplate(MATCH_MOBILE, null, null, null, METERED_ALL, + ROAMING_ALL, DEFAULT_NETWORK_ALL, 0, OEM_MANAGED_YES) + assertParcelSane(templateMobile, 9) + assertParcelSane(templateWifi, 9) + assertParcelSane(templateOem, 9) } // Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with @@ -152,4 +172,81 @@ class NetworkTemplateTest { assertNotEquals(NETWORK_TYPE_5G_NSA, ratType) } } + + @Test + fun testOemNetworkConstants() { + val constantValues = arrayOf(OEM_MANAGED_YES, OEM_MANAGED_ALL, OEM_MANAGED_NO, + OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE) + + // Verify that "not OEM managed network" constants are equal. + assertEquals(OEM_MANAGED_NO, OEM_NONE); + + // Verify the constants don't conflict. + assertEquals(constantValues.size, constantValues.distinct().count()) + } + + /** + * Helper to enumerate and assert OEM managed wifi and mobile {@code NetworkTemplate}s match + * their the appropriate OEM managed {@code NetworkIdentity}s. + * + * @param networkType {@code TYPE_MOBILE} or {@code TYPE_WIFI} + * @param matchType A match rule from {@code NetworkTemplate.MATCH_*} corresponding to the + * networkType. + * @param subscriberId To be populated with {@code TEST_IMSI*} only if networkType is + * {@code TYPE_MOBILE}. May be left as null when matchType is + * {@link NetworkTemplate.MATCH_MOBILE_WILDCARD}. + * @param templateSsid Top be populated with {@code TEST_SSID*} only if networkType is + * {@code TYPE_WIFI}. May be left as null when matchType is + * {@link NetworkTemplate.MATCH_WIFI_WILDCARD}. + * @param identSsid If networkType is {@code TYPE_WIFI}, this value must *NOT* be null. Provide + * one of {@code TEST_SSID*}. + */ + private fun matchOemManagedIdent(networkType: Int, matchType:Int, subscriberId: String? = null, + templateSsid: String? = null, identSsid: String? = null) { + val oemManagedStates = arrayOf(OEM_NONE, OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE) + // A null subscriberId needs a null matchSubscriberIds argument as well. + val matchSubscriberIds = if (subscriberId == null) null else arrayOf(subscriberId) + + val templateOemYes = NetworkTemplate(matchType, subscriberId, matchSubscriberIds, + templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, + OEM_MANAGED_YES) + val templateOemAll = NetworkTemplate(matchType, subscriberId, matchSubscriberIds, + templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, + OEM_MANAGED_ALL) + + for (identityOemManagedState in oemManagedStates) { + val ident = buildNetworkIdentity(mockContext, buildNetworkState(networkType, + subscriberId, identSsid, identityOemManagedState), /*defaultNetwork=*/false, + /*subType=*/0) + + // Create a template with each OEM managed type and match it against the NetworkIdentity + for (templateOemManagedState in oemManagedStates) { + val template = NetworkTemplate(matchType, subscriberId, matchSubscriberIds, + templateSsid, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, + NETWORK_TYPE_ALL, templateOemManagedState) + if (identityOemManagedState == templateOemManagedState) { + template.assertMatches(ident) + } else { + template.assertDoesNotMatch(ident) + } + } + // OEM_MANAGED_ALL ignores OEM state. + templateOemAll.assertMatches(ident) + if (identityOemManagedState == OEM_NONE) { + // OEM_MANAGED_YES matches everything except OEM_NONE. + templateOemYes.assertDoesNotMatch(ident) + } else { + templateOemYes.assertMatches(ident) + } + } + } + + @Test + fun testOemManagedMatchesIdent() { + matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE, subscriberId = TEST_IMSI1) + matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE_WILDCARD) + matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI, templateSsid = TEST_SSID1, + identSsid = TEST_SSID1) + matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI_WILDCARD, identSsid = TEST_SSID1) + } } diff --git a/tests/net/java/android/net/VpnTransportInfoTest.java b/tests/net/java/android/net/VpnTransportInfoTest.java index 866f38c84333..d04c87b29c25 100644 --- a/tests/net/java/android/net/VpnTransportInfoTest.java +++ b/tests/net/java/android/net/VpnTransportInfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * 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. diff --git a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt new file mode 100644 index 000000000000..9b0cfa9db30f --- /dev/null +++ b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt @@ -0,0 +1,137 @@ +/* + * 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.net.util + +import android.content.Context +import android.content.res.Resources +import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER +import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE +import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY +import android.net.util.MultinetworkPolicyTracker.ActiveDataSubscriptionIdChangedListener +import android.provider.Settings +import android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI +import android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE +import android.telephony.SubscriptionInfo +import android.telephony.SubscriptionManager +import android.telephony.TelephonyManager +import android.test.mock.MockContentResolver +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.internal.R +import com.android.internal.util.test.FakeSettingsProvider +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.argThat +import org.mockito.Mockito.any +import org.mockito.Mockito.doReturn +import org.mockito.Mockito.mock +import org.mockito.Mockito.times +import org.mockito.Mockito.verify + +/** + * Tests for [MultinetworkPolicyTracker]. + * + * Build, install and run with: + * atest android.net.util.MultinetworkPolicyTrackerTest + */ +@RunWith(AndroidJUnit4::class) +@SmallTest +class MultinetworkPolicyTrackerTest { + private val resources = mock(Resources::class.java).also { + doReturn(0).`when`(it).getInteger(R.integer.config_networkAvoidBadWifi) + } + private val telephonyManager = mock(TelephonyManager::class.java) + private val subscriptionManager = mock(SubscriptionManager::class.java).also { + doReturn(null).`when`(it).getActiveSubscriptionInfo(anyInt()) + } + private val resolver = MockContentResolver().apply { + addProvider(Settings.AUTHORITY, FakeSettingsProvider()) } + private val context = mock(Context::class.java).also { + doReturn(Context.TELEPHONY_SERVICE).`when`(it) + .getSystemServiceName(TelephonyManager::class.java) + doReturn(telephonyManager).`when`(it).getSystemService(Context.TELEPHONY_SERVICE) + doReturn(subscriptionManager).`when`(it) + .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) + doReturn(resolver).`when`(it).contentResolver + doReturn(resources).`when`(it).resources + doReturn(it).`when`(it).createConfigurationContext(any()) + Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "1") + } + private val tracker = MultinetworkPolicyTracker(context, null /* handler */) + + private fun assertMultipathPreference(preference: Int) { + Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE, + preference.toString()) + tracker.updateMeteredMultipathPreference() + assertEquals(preference, tracker.meteredMultipathPreference) + } + + @Test + fun testUpdateMeteredMultipathPreference() { + assertMultipathPreference(MULTIPATH_PREFERENCE_HANDOVER) + assertMultipathPreference(MULTIPATH_PREFERENCE_RELIABILITY) + assertMultipathPreference(MULTIPATH_PREFERENCE_PERFORMANCE) + } + + @Test + fun testUpdateAvoidBadWifi() { + Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0") + assertTrue(tracker.updateAvoidBadWifi()) + assertFalse(tracker.avoidBadWifi) + + doReturn(1).`when`(resources).getInteger(R.integer.config_networkAvoidBadWifi) + assertTrue(tracker.updateAvoidBadWifi()) + assertTrue(tracker.avoidBadWifi) + } + + @Test + fun testOnActiveDataSubscriptionIdChanged() { + val testSubId = 1000 + val subscriptionInfo = SubscriptionInfo(testSubId, ""/* iccId */, 1/* iccId */, + "TMO"/* displayName */, "TMO"/* carrierName */, 1/* nameSource */, 1/* iconTint */, + "123"/* number */, 1/* roaming */, null/* icon */, "310"/* mcc */, "210"/* mnc */, + ""/* countryIso */, false/* isEmbedded */, null/* nativeAccessRules */, + "1"/* cardString */) + doReturn(subscriptionInfo).`when`(subscriptionManager).getActiveSubscriptionInfo(testSubId) + + // Modify avoidBadWifi and meteredMultipathPreference settings value and local variables in + // MultinetworkPolicyTracker should be also updated after subId changed. + Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "0") + Settings.Global.putString(resolver, NETWORK_METERED_MULTIPATH_PREFERENCE, + MULTIPATH_PREFERENCE_PERFORMANCE.toString()) + + val listenerCaptor = ArgumentCaptor.forClass( + ActiveDataSubscriptionIdChangedListener::class.java) + verify(telephonyManager, times(1)) + .registerPhoneStateListener(any(), listenerCaptor.capture()) + val listener = listenerCaptor.value + listener.onActiveDataSubscriptionIdChanged(testSubId) + + // Check it get resource value with test sub id. + verify(subscriptionManager, times(1)).getActiveSubscriptionInfo(testSubId) + verify(context).createConfigurationContext(argThat { it.mcc == 310 && it.mnc == 210 }) + + // Check if avoidBadWifi and meteredMultipathPreference values have been updated. + assertFalse(tracker.avoidBadWifi) + assertEquals(MULTIPATH_PREFERENCE_PERFORMANCE, tracker.meteredMultipathPreference) + } +} diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 88ccf8ec77b3..bb822d85b602 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -406,6 +406,8 @@ public class ConnectivityServiceTest { private QosCallbackMockHelper mQosCallbackMockHelper; private QosCallbackTracker mQosCallbackTracker; private VpnManagerService mVpnManagerService; + private TestNetworkCallback mDefaultNetworkCallback; + private TestNetworkCallback mSystemDefaultNetworkCallback; // State variables required to emulate NetworkPolicyManagerService behaviour. private int mUidRules = RULE_NONE; @@ -1546,6 +1548,7 @@ public class ConnectivityServiceTest { @After public void tearDown() throws Exception { + unregisterDefaultNetworkCallbacks(); setAlwaysOnNetworks(false); if (mCellNetworkAgent != null) { mCellNetworkAgent.disconnect(); @@ -2795,6 +2798,10 @@ public class ConnectivityServiceTest { NetworkCapabilities filter = new NetworkCapabilities(); filter.addCapability(capability); + // Add NOT_VCN_MANAGED capability into filter unconditionally since some request will add + // NOT_VCN_MANAGED automatically but not for NetworkCapabilities, + // see {@code NetworkCapabilities#deduceNotVcnManagedCapability} for more details. + filter.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests"); handlerThread.start(); final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(), @@ -4141,6 +4148,7 @@ public class ConnectivityServiceTest { handlerThread.start(); NetworkCapabilities filter = new NetworkCapabilities() .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) .addCapability(NET_CAPABILITY_INTERNET); final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(), mServiceContext, "testFactory", filter, mCsHandlerThread); @@ -6045,6 +6053,7 @@ public class ConnectivityServiceTest { .addTransportType(TRANSPORT_CELLULAR) .addCapability(NET_CAPABILITY_INTERNET) .addCapability(NET_CAPABILITY_NOT_CONGESTED) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) .setLinkDownstreamBandwidthKbps(10); final NetworkCapabilities wifiNc = new NetworkCapabilities() .addTransportType(TRANSPORT_WIFI) @@ -6053,6 +6062,7 @@ public class ConnectivityServiceTest { .addCapability(NET_CAPABILITY_NOT_ROAMING) .addCapability(NET_CAPABILITY_NOT_CONGESTED) .addCapability(NET_CAPABILITY_NOT_SUSPENDED) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) .setLinkUpstreamBandwidthKbps(20); mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */); mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */); @@ -6851,7 +6861,7 @@ public class ConnectivityServiceTest { callback.expectCapabilitiesThat(mMockVpn, (caps) -> caps.getUids().size() == 2 && caps.getUids().contains(new UidRange(uid, uid)) - && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER)) + && caps.getUids().contains(createUidRange(RESTRICTED_USER)) && caps.hasTransport(TRANSPORT_VPN) && caps.hasTransport(TRANSPORT_WIFI)); @@ -6861,7 +6871,7 @@ public class ConnectivityServiceTest { callback.expectCapabilitiesThat(mMockVpn, (caps) -> caps.getUids().size() == 2 && caps.getUids().contains(new UidRange(uid, uid)) - && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER)) + && caps.getUids().contains(createUidRange(RESTRICTED_USER)) && caps.hasTransport(TRANSPORT_VPN) && !caps.hasTransport(TRANSPORT_WIFI)); @@ -7495,7 +7505,7 @@ public class ConnectivityServiceTest { assertNotNull(underlying); mMockVpn.setVpnType(VpnManager.TYPE_VPN_LEGACY); // The legacy lockdown VPN only supports userId 0. - final Set<UidRange> ranges = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); + final Set<UidRange> ranges = Collections.singleton(createUidRange(PRIMARY_USER)); mMockVpn.registerAgent(ranges); mMockVpn.setUnderlyingNetworks(new Network[]{underlying}); mMockVpn.connect(true); @@ -7745,19 +7755,13 @@ public class ConnectivityServiceTest { mWiFiNetworkAgent.removeCapability(testCap); callbackWithCap.expectAvailableCallbacksValidated(mCellNetworkAgent); callbackWithoutCap.expectCapabilitiesWithout(testCap, mWiFiNetworkAgent); - // TODO: Test default network changes for NOT_VCN_MANAGED once the default request has - // it. - if (testCap == NET_CAPABILITY_TRUSTED) { - verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId)); - reset(mMockNetd); - } + verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId)); + reset(mMockNetd); mCellNetworkAgent.removeCapability(testCap); callbackWithCap.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); callbackWithoutCap.assertNoCallback(); - if (testCap == NET_CAPABILITY_TRUSTED) { - verify(mMockNetd).networkClearDefault(); - } + verify(mMockNetd).networkClearDefault(); mCm.unregisterNetworkCallback(callbackWithCap); mCm.unregisterNetworkCallback(callbackWithoutCap); @@ -8414,7 +8418,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); + final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); mMockVpn.establish(lp, VPN_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, VPN_UID); @@ -8442,7 +8446,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); + final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID); @@ -8458,7 +8462,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0")); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); + final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID); @@ -8473,7 +8477,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); + final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); mMockVpn.establish(lp, VPN_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, VPN_UID); @@ -8525,7 +8529,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. - final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER); + final UidRange vpnRange = createUidRange(PRIMARY_USER); final Set<UidRange> vpnRanges = Collections.singleton(vpnRange); mMockVpn.establish(lp, VPN_UID, vpnRanges); assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID); @@ -8724,7 +8728,7 @@ public class ConnectivityServiceTest { private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType) throws Exception { - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); + final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); mMockVpn.setVpnType(vpnType); mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid); @@ -9283,7 +9287,7 @@ public class ConnectivityServiceTest { lp.setInterfaceName("tun0"); lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); - final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER); + final UidRange vpnRange = createUidRange(PRIMARY_USER); Set<UidRange> vpnRanges = Collections.singleton(vpnRange); mMockVpn.establish(lp, VPN_UID, vpnRanges); assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID); @@ -9463,6 +9467,10 @@ public class ConnectivityServiceTest { fail("TOO_MANY_REQUESTS never thrown"); } + private UidRange createUidRange(int userId) { + return UidRange.createForUser(UserHandle.of(userId)); + } + private void mockGetApplicationInfo(@NonNull final String packageName, @NonNull final int uid) throws Exception { final ApplicationInfo applicationInfo = new ApplicationInfo(); @@ -9797,6 +9805,54 @@ public class ConnectivityServiceTest { assertEquals(expectedPerAppNetwork, defaultNetwork); assertEquals(expectedOemRequestsSize, defaultRequest.mRequests.size()); } + verifyMultipleDefaultCallbacks(expectedDefaultNetwork, expectedPerAppNetwork); + } + + /** + * Verify default callbacks for 'available' fire as expected. This will only run if + * registerDefaultNetworkCallbacks() was executed prior and will only be different if the + * setOemNetworkPreference() per-app API was used for the current process. + * @param expectedSystemDefault the expected network for the system default. + * @param expectedPerAppDefault the expected network for the current process's default. + */ + private void verifyMultipleDefaultCallbacks( + @NonNull final Network expectedSystemDefault, + @NonNull final Network expectedPerAppDefault) { + if (null != mSystemDefaultNetworkCallback && null != expectedSystemDefault + && mService.mNoServiceNetwork.network() != expectedSystemDefault) { + // getLastAvailableNetwork() is used as this method can be called successively with + // the same network to validate therefore expectAvailableThenValidatedCallbacks + // can't be used. + assertEquals(mSystemDefaultNetworkCallback.getLastAvailableNetwork(), + expectedSystemDefault); + } + if (null != mDefaultNetworkCallback && null != expectedPerAppDefault + && mService.mNoServiceNetwork.network() != expectedPerAppDefault) { + assertEquals(mDefaultNetworkCallback.getLastAvailableNetwork(), + expectedPerAppDefault); + } + } + + private void registerDefaultNetworkCallbacks() { + // Using Manifest.permission.NETWORK_SETTINGS for registerSystemDefaultNetworkCallback() + mServiceContext.setPermission( + Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED); + mSystemDefaultNetworkCallback = new TestNetworkCallback(); + mDefaultNetworkCallback = new TestNetworkCallback(); + mCm.registerSystemDefaultNetworkCallback(mSystemDefaultNetworkCallback, + new Handler(ConnectivityThread.getInstanceLooper())); + mCm.registerDefaultNetworkCallback(mDefaultNetworkCallback); + mServiceContext.setPermission( + Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED); + } + + private void unregisterDefaultNetworkCallbacks() { + if (null != mDefaultNetworkCallback) { + mCm.unregisterNetworkCallback(mDefaultNetworkCallback); + } + if (null != mSystemDefaultNetworkCallback) { + mCm.unregisterNetworkCallback(mSystemDefaultNetworkCallback); + } } private void setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest( @@ -9880,6 +9936,7 @@ public class ConnectivityServiceTest { @OemNetworkPreferences.OemNetworkPreference final int networkPref = OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY; final int expectedOemPrefRequestSize = 1; + registerDefaultNetworkCallbacks(); // Setup the test process to use networkPref for their default network. setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref); @@ -9894,6 +9951,7 @@ public class ConnectivityServiceTest { // Verify that the active network is correct verifyActiveNetwork(TRANSPORT_ETHERNET); + // default NCs will be unregistered in tearDown } @Test @@ -9901,6 +9959,7 @@ public class ConnectivityServiceTest { @OemNetworkPreferences.OemNetworkPreference final int networkPref = OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY; final int expectedOemPrefRequestSize = 1; + registerDefaultNetworkCallbacks(); // Setup the test process to use networkPref for their default network. setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref); @@ -9921,6 +9980,7 @@ public class ConnectivityServiceTest { mEthernetNetworkAgent.getNetwork()); assertFalse(mCm.isActiveNetworkMetered()); + // default NCs will be unregistered in tearDown } @Test @@ -10077,7 +10137,6 @@ public class ConnectivityServiceTest { /** * Test the tracked default requests clear previous OEM requests on setOemNetworkPreference(). - * @throws Exception */ @Test public void testSetOemNetworkPreferenceClearPreviousOemValues() throws Exception { @@ -10105,9 +10164,8 @@ public class ConnectivityServiceTest { } /** - * Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID following in order: + * Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID in the following order: * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID -> fallback - * @throws Exception */ @Test public void testMultilayerForPreferenceOemPaidEvaluatesCorrectly() @@ -10173,9 +10231,8 @@ public class ConnectivityServiceTest { } /** - * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK following in order: + * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK in the following order: * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID - * @throws Exception */ @Test public void testMultilayerForPreferenceOemPaidNoFallbackEvaluatesCorrectly() @@ -10236,10 +10293,9 @@ public class ConnectivityServiceTest { } /** - * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY following in order: + * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY in the following order: * NET_CAPABILITY_OEM_PAID * This preference should only apply to OEM_PAID networks. - * @throws Exception */ @Test public void testMultilayerForPreferenceOemPaidOnlyEvaluatesCorrectly() @@ -10290,10 +10346,9 @@ public class ConnectivityServiceTest { } /** - * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY following in order: + * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY in the following order: * NET_CAPABILITY_OEM_PRIVATE * This preference should only apply to OEM_PRIVATE networks. - * @throws Exception */ @Test public void testMultilayerForPreferenceOemPrivateOnlyEvaluatesCorrectly() @@ -10342,4 +10397,236 @@ public class ConnectivityServiceTest { mEthernetNetworkAgent.getNetwork().netId, 0 /* times */, true /* shouldDestroyNetwork */); } + + /** + * Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID in the following order: + * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID -> fallback + */ + @Test + public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPaidCorrectly() + throws Exception { + @OemNetworkPreferences.OemNetworkPreference final int networkPref = + OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID; + setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref); + final int expectedDefaultRequestSize = 2; + final int expectedOemPrefRequestSize = 3; + registerDefaultNetworkCallbacks(); + + // The fallback as well as the OEM preference should now be tracked. + assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size()); + + // Test lowest to highest priority requests. + // Bring up metered cellular. This will satisfy the fallback network. + setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mCellNetworkAgent.getNetwork(), + mCellNetworkAgent.getNetwork()); + + // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID. + setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mCellNetworkAgent.getNetwork(), + mEthernetNetworkAgent.getNetwork()); + + // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED. + setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mWiFiNetworkAgent.getNetwork(), + mWiFiNetworkAgent.getNetwork()); + + // Disconnecting unmetered Wi-Fi will put the pref on OEM_PAID and fallback on cellular. + setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mCellNetworkAgent.getNetwork(), + mEthernetNetworkAgent.getNetwork()); + + // Disconnecting cellular should keep OEM network on OEM_PAID and fallback will be null. + setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + null, + mEthernetNetworkAgent.getNetwork()); + + // Disconnecting OEM_PAID will put both on null as it is the last network. + setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + null, + null); + + // default NCs will be unregistered in tearDown + } + + /** + * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK in the following order: + * NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID + */ + @Test + public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPaidNoFallbackCorrectly() + throws Exception { + @OemNetworkPreferences.OemNetworkPreference final int networkPref = + OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK; + setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref); + final int expectedDefaultRequestSize = 2; + final int expectedOemPrefRequestSize = 2; + registerDefaultNetworkCallbacks(); + + // The fallback as well as the OEM preference should now be tracked. + assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size()); + + // Test lowest to highest priority requests. + // Bring up metered cellular. This will satisfy the fallback network but not the pref. + setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mCellNetworkAgent.getNetwork(), + mService.mNoServiceNetwork.network()); + + // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID. + setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mCellNetworkAgent.getNetwork(), + mEthernetNetworkAgent.getNetwork()); + + // Bring up unmetered Wi-Fi. This will satisfy NET_CAPABILITY_NOT_METERED. + setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mWiFiNetworkAgent.getNetwork(), + mWiFiNetworkAgent.getNetwork()); + + // Disconnecting unmetered Wi-Fi will put the OEM pref on OEM_PAID and fallback on cellular. + setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mCellNetworkAgent.getNetwork(), + mEthernetNetworkAgent.getNetwork()); + + // Disconnecting cellular should keep OEM network on OEM_PAID and fallback will be null. + setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + null, + mEthernetNetworkAgent.getNetwork()); + + // Disconnecting OEM_PAID puts the fallback on null and the pref on the disconnected net. + setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + null, + mService.mNoServiceNetwork.network()); + + // default NCs will be unregistered in tearDown + } + + /** + * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY in the following order: + * NET_CAPABILITY_OEM_PAID + * This preference should only apply to OEM_PAID networks. + */ + @Test + public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPaidOnlyCorrectly() + throws Exception { + @OemNetworkPreferences.OemNetworkPreference final int networkPref = + OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY; + setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref); + final int expectedDefaultRequestSize = 2; + final int expectedOemPrefRequestSize = 1; + registerDefaultNetworkCallbacks(); + + // The fallback as well as the OEM preference should now be tracked. + assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size()); + + // Test lowest to highest priority requests. + // Bring up metered cellular. This will satisfy the fallback network. + setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mCellNetworkAgent.getNetwork(), + mService.mNoServiceNetwork.network()); + + // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID. + setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mCellNetworkAgent.getNetwork(), + mEthernetNetworkAgent.getNetwork()); + + // Bring up unmetered Wi-Fi. The OEM network shouldn't change, the fallback will take Wi-Fi. + setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mWiFiNetworkAgent.getNetwork(), + mEthernetNetworkAgent.getNetwork()); + + // Disconnecting unmetered Wi-Fi shouldn't change the OEM network with fallback on cellular. + setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mCellNetworkAgent.getNetwork(), + mEthernetNetworkAgent.getNetwork()); + + // Disconnecting OEM_PAID will keep the fallback on cellular and nothing for OEM_PAID. + // OEM_PAID_ONLY not supporting a fallback now uses the disconnected network. + setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mCellNetworkAgent.getNetwork(), + mService.mNoServiceNetwork.network()); + + // Disconnecting cellular will put the fallback on null and the pref on disconnected. + setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + null, + mService.mNoServiceNetwork.network()); + + // default NCs will be unregistered in tearDown + } + + /** + * Test network priority for OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY in the following order: + * NET_CAPABILITY_OEM_PRIVATE + * This preference should only apply to OEM_PRIVATE networks. + */ + @Test + public void testMultipleDefaultNetworksTracksOemNetworkPreferenceOemPrivateOnlyCorrectly() + throws Exception { + @OemNetworkPreferences.OemNetworkPreference final int networkPref = + OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY; + setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref); + final int expectedDefaultRequestSize = 2; + final int expectedOemPrefRequestSize = 1; + registerDefaultNetworkCallbacks(); + + // The fallback as well as the OEM preference should now be tracked. + assertEquals(expectedDefaultRequestSize, mService.mDefaultNetworkRequests.size()); + + // Test lowest to highest priority requests. + // Bring up metered cellular. This will satisfy the fallback network. + setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mCellNetworkAgent.getNetwork(), + mService.mNoServiceNetwork.network()); + + // Bring up ethernet with OEM_PRIVATE. This will satisfy NET_CAPABILITY_OEM_PRIVATE. + startOemManagedNetwork(false); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mCellNetworkAgent.getNetwork(), + mEthernetNetworkAgent.getNetwork()); + + // Bring up unmetered Wi-Fi. The OEM network shouldn't change, the fallback will take Wi-Fi. + setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, true); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mWiFiNetworkAgent.getNetwork(), + mEthernetNetworkAgent.getNetwork()); + + // Disconnecting unmetered Wi-Fi shouldn't change the OEM network with fallback on cellular. + setOemNetworkPreferenceAgentConnected(TRANSPORT_WIFI, false); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mCellNetworkAgent.getNetwork(), + mEthernetNetworkAgent.getNetwork()); + + // Disconnecting OEM_PRIVATE will keep the fallback on cellular. + // OEM_PRIVATE_ONLY not supporting a fallback now uses to the disconnected network. + stopOemManagedNetwork(); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + mCellNetworkAgent.getNetwork(), + mService.mNoServiceNetwork.network()); + + // Disconnecting cellular will put the fallback on null and pref on disconnected. + setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false); + verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, + null, + mService.mNoServiceNetwork.network()); + + // default NCs will be unregistered in tearDown + } } diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 6576daf5ab9a..7489a0f889dc 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -182,7 +182,8 @@ public class VpnTest { mPackages.put(PKGS[i], PKG_UIDS[i]); } } - private static final UidRange PRI_USER_RANGE = UidRange.createForUser(primaryUser.id); + private static final UidRange PRI_USER_RANGE = + UidRange.createForUser(UserHandle.of(primaryUser.id)); @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock private UserManager mUserManager; @@ -272,7 +273,7 @@ public class VpnTest { vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null); assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { - PRI_USER_RANGE, UidRange.createForUser(restrictedProfileA.id) + PRI_USER_RANGE, UidRange.createForUser(UserHandle.of(restrictedProfileA.id)) })), ranges); } diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java index 435c3c0af817..505ff9b6a34b 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java @@ -17,6 +17,7 @@ package com.android.server.net; import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.net.NetworkIdentity.OEM_NONE; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_NONE; @@ -213,7 +214,7 @@ public class NetworkStatsCollectionTest { final NetworkStats.Entry entry = new NetworkStats.Entry(); final NetworkIdentitySet identSet = new NetworkIdentitySet(); identSet.add(new NetworkIdentity(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, - TEST_IMSI, null, false, true, true)); + TEST_IMSI, null, false, true, true, OEM_NONE)); int myUid = Process.myUid(); int otherUidInSameUser = Process.myUid() + 1; @@ -468,7 +469,7 @@ public class NetworkStatsCollectionTest { final NetworkStatsCollection large = new NetworkStatsCollection(HOUR_IN_MILLIS); final NetworkIdentitySet ident = new NetworkIdentitySet(); ident.add(new NetworkIdentity(ConnectivityManager.TYPE_MOBILE, -1, TEST_IMSI, null, - false, true, true)); + false, true, true, OEM_NONE)); large.recordData(ident, UID_ALL, SET_ALL, TAG_NONE, TIME_A, TIME_B, new NetworkStats.Entry(12_730_893_164L, 1, 0, 0, 0)); diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java index 291efc74aa47..9fa1c50423d9 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java @@ -17,6 +17,7 @@ package com.android.server.net; import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.net.NetworkIdentity.OEM_NONE; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.DEFAULT_NETWORK_YES; import static android.net.NetworkStats.METERED_NO; @@ -220,7 +221,7 @@ public class NetworkStatsObserversTest { identSet.add(new NetworkIdentity( TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, IMSI_1, null /* networkId */, false /* roaming */, true /* metered */, - true /* defaultNetwork */)); + true /* defaultNetwork */, OEM_NONE)); return identSet; } diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index d644739ea25e..54d6fb9f2c12 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -21,6 +21,9 @@ 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.NetworkIdentity.OEM_NONE; +import static android.net.NetworkIdentity.OEM_PAID; +import static android.net.NetworkIdentity.OEM_PRIVATE; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.DEFAULT_NETWORK_YES; @@ -40,7 +43,10 @@ import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStatsHistory.FIELD_ALL; +import static android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD; import static android.net.NetworkTemplate.NETWORK_TYPE_ALL; +import static android.net.NetworkTemplate.OEM_MANAGED_NO; +import static android.net.NetworkTemplate.OEM_MANAGED_YES; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateMobileWithRatType; import static android.net.NetworkTemplate.buildTemplateWifi; @@ -643,6 +649,116 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { assertUidTotal(template5g, UID_RED, 5L, 13L, 31L, 9L, 2); } + @Test + public void testMobileStatsOemManaged() throws Exception { + final NetworkTemplate templateOemPaid = new NetworkTemplate(MATCH_MOBILE_WILDCARD, + /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null, + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PAID); + + final NetworkTemplate templateOemPrivate = new NetworkTemplate(MATCH_MOBILE_WILDCARD, + /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null, + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_PRIVATE); + + final NetworkTemplate templateOemAll = new NetworkTemplate(MATCH_MOBILE_WILDCARD, + /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null, + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, + OEM_PAID | OEM_PRIVATE); + + final NetworkTemplate templateOemYes = new NetworkTemplate(MATCH_MOBILE_WILDCARD, + /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null, + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_YES); + + final NetworkTemplate templateOemNone = new NetworkTemplate(MATCH_MOBILE_WILDCARD, + /*subscriberId=*/null, /*matchSubscriberIds=*/null, /*networkId=*/null, + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_NO); + + // OEM_PAID network comes online. + NetworkState[] states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false, + new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PAID})}; + expectNetworkStatsSummary(buildEmptyStats()); + expectNetworkStatsUidDetail(buildEmptyStats()); + mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + new UnderlyingNetworkInfo[0]); + + // Create some traffic. + incrementCurrentTime(MINUTE_IN_MILLIS); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) + .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, + 36L, 41L, 24L, 96L, 0L))); + forcePollAndWaitForIdle(); + + // OEM_PRIVATE network comes online. + states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false, + new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE})}; + expectNetworkStatsSummary(buildEmptyStats()); + expectNetworkStatsUidDetail(buildEmptyStats()); + mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + new UnderlyingNetworkInfo[0]); + + // Create some traffic. + incrementCurrentTime(MINUTE_IN_MILLIS); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) + .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, + 49L, 71L, 72L, 48L, 0L))); + forcePollAndWaitForIdle(); + + // OEM_PAID + OEM_PRIVATE network comes online. + states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false, + new int[]{NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE, + NetworkCapabilities.NET_CAPABILITY_OEM_PAID})}; + expectNetworkStatsSummary(buildEmptyStats()); + expectNetworkStatsUidDetail(buildEmptyStats()); + mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + new UnderlyingNetworkInfo[0]); + + // Create some traffic. + incrementCurrentTime(MINUTE_IN_MILLIS); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) + .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, + 57L, 86L, 83L, 93L, 0L))); + forcePollAndWaitForIdle(); + + // OEM_NONE network comes online. + states = new NetworkState[]{buildOemManagedMobileState(IMSI_1, false, new int[]{})}; + expectNetworkStatsSummary(buildEmptyStats()); + expectNetworkStatsUidDetail(buildEmptyStats()); + mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + new UnderlyingNetworkInfo[0]); + + // Create some traffic. + incrementCurrentTime(MINUTE_IN_MILLIS); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) + .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, + 29L, 73L, 34L, 31L, 0L))); + forcePollAndWaitForIdle(); + + // Verify OEM_PAID template gets only relevant stats. + assertUidTotal(templateOemPaid, UID_RED, 36L, 41L, 24L, 96L, 0); + + // Verify OEM_PRIVATE template gets only relevant stats. + assertUidTotal(templateOemPrivate, UID_RED, 49L, 71L, 72L, 48L, 0); + + // Verify OEM_PAID + OEM_PRIVATE template gets only relevant stats. + assertUidTotal(templateOemAll, UID_RED, 57L, 86L, 83L, 93L, 0); + + // Verify OEM_NONE sees only non-OEM managed stats. + assertUidTotal(templateOemNone, UID_RED, 29L, 73L, 34L, 31L, 0); + + // Verify OEM_MANAGED_YES sees all OEM managed stats. + assertUidTotal(templateOemYes, UID_RED, + 36L + 49L + 57L, + 41L + 71L + 86L, + 24L + 72L + 83L, + 96L + 48L + 93L, 0); + + // Verify ALL_MOBILE template gets both OEM managed and non-OEM managed stats. + assertUidTotal(sTemplateImsi1, UID_RED, + 36L + 49L + 57L + 29L, + 41L + 71L + 86L + 73L, + 24L + 72L + 83L + 34L, + 96L + 48L + 93L + 31L, 0); + } + // TODO: support per IMSI state private void setMobileRatTypeAndWaitForIdle(int ratType) { when(mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(anyString())) @@ -1488,6 +1604,20 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { return new NetworkState(TYPE_VPN, prop, new NetworkCapabilities(), VPN_NETWORK, null); } + private static NetworkState buildOemManagedMobileState(String subscriberId, boolean isRoaming, + int[] oemNetCapabilities) { + final LinkProperties prop = new LinkProperties(); + prop.setInterfaceName(TEST_IFACE); + final NetworkCapabilities capabilities = new NetworkCapabilities(); + capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false); + capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming); + for (int nc : oemNetCapabilities) { + capabilities.setCapability(nc, true); + } + capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); + return new NetworkState(TYPE_MOBILE, prop, capabilities, MOBILE_NETWORK, subscriberId); + } + private long getElapsedRealtime() { return mElapsedRealtime; } diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java index ce8a898de2ed..66590c92579b 100644 --- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java +++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java @@ -16,6 +16,8 @@ package android.net.vcn; +import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE; + import static androidx.test.InstrumentationRegistry.getContext; import static org.junit.Assert.assertEquals; @@ -204,6 +206,9 @@ public class VcnManagerTest { cbBinder.onEnteredSafeMode(); verify(mMockStatusCallback).onEnteredSafeMode(); + cbBinder.onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE); + verify(mMockStatusCallback).onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE); + cbBinder.onGatewayConnectionError( UNDERLYING_NETWORK_CAPABILITIES, VcnManager.VCN_ERROR_CODE_NETWORK_ERROR, diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index 45b2381ce06d..9b500a7271d7 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -43,7 +43,6 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -59,6 +58,7 @@ import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.net.vcn.VcnConfigTest; +import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.net.wifi.WifiInfo; import android.os.IBinder; @@ -783,7 +783,7 @@ public class VcnManagementServiceTest { true /* hasPermissionsforSubGroup */, true /* hasLocationPermission */); - verify(mMockStatusCallback, times(1)).onEnteredSafeMode(); + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); } @Test @@ -795,7 +795,8 @@ public class VcnManagementServiceTest { false /* hasPermissionsforSubGroup */, true /* hasLocationPermission */); - verify(mMockStatusCallback, never()).onEnteredSafeMode(); + verify(mMockStatusCallback, never()) + .onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); } @Test @@ -807,7 +808,8 @@ public class VcnManagementServiceTest { true /* hasPermissionsforSubGroup */, false /* hasLocationPermission */); - verify(mMockStatusCallback, never()).onEnteredSafeMode(); + verify(mMockStatusCallback, never()) + .onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); } @Test diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py index a4a315b7e371..7de706502618 100755 --- a/tools/fonts/fontchain_linter.py +++ b/tools/fonts/fontchain_linter.py @@ -11,6 +11,12 @@ from fontTools import ttLib EMOJI_VS = 0xFE0F +#TODO(179952916): Rename CutiveMono and DancingScript +CANONICAL_NAME_EXCEPTION_LIST = [ + 'CutiveMono.ttf', + 'DancingScript-Regular.ttf', +] + LANG_TO_SCRIPT = { 'as': 'Beng', 'be': 'Cyrl', @@ -658,6 +664,53 @@ def check_cjk_punctuation(): assert_font_supports_none_of_chars(record.font, cjk_punctuation, name) +def getPostScriptName(font): + ttf = open_font(font) + nameTable = ttf['name'] + for name in nameTable.names: + if name.nameID == 6 and name.platformID == 3 and name.platEncID == 1 and name.langID == 0x0409: + return str(name) + + +def getSuffix(font): + file_path, index = font + with open(path.join(_fonts_dir, file_path), 'rb') as f: + tag = f.read(4) + isCollection = tag == b'ttcf' + + ttf = open_font(font) + isType1 = ('CFF ' in ttf or 'CFF2' in ttf) + + if isType1: + if isCollection: + return '.otc' + else: + return '.otf' + else: + if isCollection: + return '.ttc' + else: + return '.ttf' + + +def check_canonical_name(): + for record in _all_fonts: + file_name, index = record.font + if file_name in CANONICAL_NAME_EXCEPTION_LIST: + continue + + if index and index != 0: + continue + + psName = getPostScriptName(record.font) + assert psName, 'PostScript must be defined' + + suffix = getSuffix(record.font) + canonicalName = '%s%s' % (psName, suffix) + + assert file_name == canonicalName, ( + '%s is not a canonical name. Must be %s' % (file_name, canonicalName)) + def main(): global _fonts_dir target_out = sys.argv[1] @@ -675,6 +728,8 @@ def main(): check_cjk_punctuation() + check_canonical_name() + check_emoji = sys.argv[2] if check_emoji == 'true': ucd_path = sys.argv[3] |