summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp50
-rw-r--r--api/current.txt23
-rw-r--r--api/system-current.txt121
-rw-r--r--api/test-current.txt101
-rw-r--r--cmds/statsd/src/StatsService.cpp19
-rw-r--r--cmds/statsd/src/StatsService.h11
-rw-r--r--cmds/statsd/src/atoms.proto218
-rw-r--r--cmds/statsd/src/config/ConfigManager.cpp28
-rw-r--r--cmds/statsd/src/config/ConfigManager.h23
-rw-r--r--cmds/statsd/src/external/StatsPullerManager.cpp4
-rw-r--r--config/hiddenapi-greylist.txt1
-rw-r--r--core/java/android/app/KeyguardManager.java52
-rw-r--r--core/java/android/app/StatsManager.java42
-rw-r--r--core/java/android/app/SystemServiceRegistry.java9
-rw-r--r--core/java/android/app/role/IRoleManager.aidl6
-rw-r--r--core/java/android/content/ContentResolver.java1
-rw-r--r--core/java/android/content/Context.java10
-rw-r--r--core/java/android/content/Intent.java7
-rw-r--r--core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl1
-rw-r--r--core/java/android/content/rollback/IRollbackManager.aidl8
-rw-r--r--core/java/android/content/rollback/RollbackInfo.java46
-rw-r--r--core/java/android/content/rollback/RollbackManager.java70
-rw-r--r--core/java/android/database/AbstractCursor.java49
-rw-r--r--core/java/android/database/Cursor.java42
-rw-r--r--core/java/android/database/CursorWrapper.java12
-rw-r--r--core/java/android/hardware/biometrics/BiometricFaceConstants.java45
-rw-r--r--core/java/android/hardware/biometrics/BiometricManager.java34
-rw-r--r--core/java/android/hardware/biometrics/BiometricPrompt.java25
-rw-r--r--core/java/android/hardware/biometrics/IBiometricService.aidl8
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java20
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl5
-rw-r--r--core/java/android/net/DhcpResults.java158
-rw-r--r--core/java/android/net/IpSecTransform.java3
-rw-r--r--core/java/android/net/NetworkUtils.java156
-rw-r--r--core/java/android/net/StaticIpConfiguration.java66
-rw-r--r--core/java/android/net/apf/ApfCapabilities.java5
-rw-r--r--core/java/android/net/captiveportal/CaptivePortalProbeResult.java4
-rw-r--r--core/java/android/net/captiveportal/CaptivePortalProbeSpec.java16
-rw-r--r--core/java/android/net/shared/Inet4AddressUtils.java166
-rw-r--r--core/java/android/os/BugreportManager.java4
-rw-r--r--core/java/android/os/BugreportParams.java4
-rw-r--r--core/java/android/os/ExternalVibration.aidl19
-rw-r--r--core/java/android/os/ExternalVibration.java171
-rw-r--r--core/java/android/os/FileUtils.java2
-rw-r--r--core/java/android/os/IExternalVibrationController.aidl45
-rw-r--r--core/java/android/os/IExternalVibratorService.aidl63
-rw-r--r--core/java/android/os/IStatsManager.aidl17
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java2
-rw-r--r--core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java20
-rw-r--r--core/java/android/provider/CalendarContract.java3
-rw-r--r--core/java/android/provider/ContactsContract.java2
-rw-r--r--core/java/android/provider/MediaStore.java7
-rw-r--r--core/java/android/provider/Settings.java2
-rw-r--r--core/java/android/provider/VoicemailContract.java2
-rw-r--r--core/java/android/service/notification/Adjustment.java8
-rw-r--r--core/java/android/util/FeatureFlagUtils.java2
-rw-r--r--core/java/android/view/Display.java19
-rw-r--r--core/java/android/view/textclassifier/TextClassificationConstants.java39
-rw-r--r--core/java/android/view/textclassifier/TextClassifierImpl.java9
-rw-r--r--core/java/android/view/textclassifier/TextLanguage.java6
-rw-r--r--core/java/android/widget/Magnifier.java10
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl5
-rw-r--r--core/jni/Android.bp1
-rw-r--r--core/jni/android/graphics/Paint.cpp4
-rw-r--r--core/jni/android_media_AudioTrack.cpp30
-rw-r--r--core/jni/fd_utils.cpp6
-rw-r--r--core/proto/android/hardware/biometrics/enums.proto46
-rw-r--r--core/proto/android/providers/settings/secure.proto3
-rw-r--r--core/res/AndroidManifest.xml4
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java195
-rw-r--r--graphics/java/android/graphics/ColorSpace.java4
-rw-r--r--media/java/android/media/AudioTrack.java47
-rw-r--r--media/java/android/media/MediaScanner.java10
-rw-r--r--media/jni/android_media_ImageReader.cpp5
-rw-r--r--native/android/surface_control.cpp25
-rw-r--r--packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java11
-rw-r--r--packages/ExtServices/src/android/ext/services/notification/Assistant.java4
-rw-r--r--packages/NetworkStack/Android.bp1
-rw-r--r--packages/NetworkStack/TEST_MAPPING7
-rw-r--r--packages/NetworkStack/src/android/net/apf/ApfFilter.java30
-rw-r--r--packages/NetworkStack/src/android/net/dhcp/DhcpClient.java4
-rw-r--r--packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java9
-rw-r--r--packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java17
-rw-r--r--packages/NetworkStack/src/android/net/dhcp/DhcpServer.java14
-rw-r--r--packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java9
-rw-r--r--packages/NetworkStack/src/android/net/ip/IpClient.java5
-rw-r--r--packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java4
-rw-r--r--packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java27
-rw-r--r--packages/NetworkStack/src/android/net/util/NetworkStackUtils.java30
-rw-r--r--packages/NetworkStack/src/com/android/server/NetworkObserver.java87
-rw-r--r--packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java150
-rw-r--r--packages/NetworkStack/src/com/android/server/NetworkStackService.java15
-rw-r--r--packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java10
-rw-r--r--packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java6
-rw-r--r--packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java62
-rw-r--r--packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java38
-rw-r--r--packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java6
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java1
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java122
-rw-r--r--services/core/java/com/android/server/ServiceWatcher.java152
-rw-r--r--services/core/java/com/android/server/VibratorService.java188
-rw-r--r--services/core/java/com/android/server/biometrics/BiometricService.java55
-rw-r--r--services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java23
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java20
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodUtils.java19
-rw-r--r--services/core/java/com/android/server/location/GeocoderProxy.java31
-rw-r--r--services/core/java/com/android/server/location/LocationProviderProxy.java57
-rw-r--r--services/core/java/com/android/server/location/OWNERS2
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java35
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java8
-rw-r--r--services/core/java/com/android/server/notification/NotificationShellCmd.java8
-rw-r--r--services/core/java/com/android/server/role/FinancialSmsManager.java218
-rw-r--r--services/core/java/com/android/server/role/RoleManagerService.java54
-rw-r--r--services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java108
-rw-r--r--services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java83
-rw-r--r--services/core/java/com/android/server/rollback/RollbackStore.java75
-rw-r--r--services/core/java/com/android/server/stats/StatsCompanionService.java2
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java7
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java9
-rw-r--r--services/core/java/com/android/server/testharness/TestHarnessModeService.java5
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java22
-rw-r--r--services/core/java/com/android/server/wm/ActivityDisplay.java16
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java96
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java39
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartController.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java5
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java4
-rw-r--r--services/core/java/com/android/server/wm/RootActivityContainer.java46
-rw-r--r--services/core/java/com/android/server/wm/TaskRecord.java8
-rw-r--r--services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java8
-rw-r--r--services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java2
-rw-r--r--services/net/java/android/net/shared/IpConfigurationParcelableUtil.java2
-rw-r--r--services/net/java/android/net/shared/NetdService.java4
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java2
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java71
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java4
-rw-r--r--telephony/java/android/telephony/IFinancialSmsCallback.aidl34
-rw-r--r--telephony/java/android/telephony/SmsManager.java116
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java9
-rw-r--r--telephony/java/com/android/internal/telephony/ISms.aidl28
-rw-r--r--telephony/java/com/android/internal/telephony/ISmsImplBase.java14
-rw-r--r--test-mock/src/android/test/mock/MockCursor.java12
-rw-r--r--tests/DexLoggerIntegrationTests/Android.mk11
-rw-r--r--tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java11
-rw-r--r--tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java216
-rw-r--r--tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java4
-rw-r--r--tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java271
-rw-r--r--tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java7
-rw-r--r--tests/net/java/android/net/NetworkUtilsTest.java188
-rw-r--r--tests/net/java/android/net/StaticIpConfigurationTest.java8
-rw-r--r--tests/net/java/android/net/ip/IpServerTest.java2
-rw-r--r--tests/net/java/android/net/shared/Inet4AddressUtilsTest.java209
-rw-r--r--tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java2
-rw-r--r--tools/bit/aapt.cpp7
-rw-r--r--tools/bit/main.cpp36
-rw-r--r--tools/bit/make.cpp139
-rw-r--r--tools/bit/make.h26
-rw-r--r--tools/bit/print.cpp14
-rw-r--r--tools/bit/print.h1
164 files changed, 4611 insertions, 1483 deletions
diff --git a/Android.bp b/Android.bp
index a5cc89cd0ea1..6964dafced1b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -271,6 +271,7 @@ java_defaults {
"core/java/android/os/IThermalService.aidl",
"core/java/android/os/IUpdateLock.aidl",
"core/java/android/os/IUserManager.aidl",
+ ":libvibrator_aidl",
"core/java/android/os/IVibratorService.aidl",
"core/java/android/os/storage/IStorageManager.aidl",
"core/java/android/os/storage/IStorageEventListener.aidl",
@@ -561,6 +562,7 @@ java_defaults {
"telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl",
"telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl",
"telephony/java/android/telephony/ICellInfoCallback.aidl",
+ "telephony/java/android/telephony/IFinancialSmsCallback.aidl",
"telephony/java/android/telephony/INetworkService.aidl",
"telephony/java/android/telephony/INetworkServiceCallback.aidl",
"telephony/java/com/android/ims/internal/IImsCallSession.aidl",
@@ -726,7 +728,7 @@ java_defaults {
"ext",
],
- jarjar_rules: ":framework-hidl-jarjar",
+ jarjar_rules: "jarjar_rules_hidl.txt",
static_libs: [
"apex_aidl_interface-java",
@@ -738,6 +740,15 @@ java_defaults {
"android.hardware.cas-V1.0-java",
"android.hardware.contexthub-V1.0-java",
"android.hardware.health-V1.0-java-constants",
+ "android.hardware.radio-V1.0-java",
+ "android.hardware.radio-V1.1-java",
+ "android.hardware.radio-V1.2-java",
+ "android.hardware.radio-V1.3-java",
+ "android.hardware.radio-V1.4-java",
+ "android.hardware.radio.config-V1.0-java",
+ "android.hardware.radio.config-V1.1-java",
+ "android.hardware.radio.config-V1.2-java",
+ "android.hardware.radio.deprecated-V1.0-java",
"android.hardware.thermal-V1.0-java-constants",
"android.hardware.thermal-V1.0-java",
"android.hardware.thermal-V1.1-java",
@@ -746,15 +757,12 @@ java_defaults {
"android.hardware.usb-V1.0-java-constants",
"android.hardware.usb-V1.1-java-constants",
"android.hardware.usb-V1.2-java-constants",
+ "android.hardware.usb.gadget-V1.0-java",
"android.hardware.vibrator-V1.0-java",
"android.hardware.vibrator-V1.1-java",
"android.hardware.vibrator-V1.2-java",
"android.hardware.vibrator-V1.3-java",
"android.hardware.wifi-V1.0-java-constants",
- "android.hardware.radio-V1.0-java",
- "android.hardware.radio-V1.3-java",
- "android.hardware.radio-V1.4-java",
- "android.hardware.usb.gadget-V1.0-java",
"networkstack-aidl-interfaces-java",
"netd_aidl_interface-java",
"devicepolicyprotosnano",
@@ -789,8 +797,11 @@ filegroup {
}
filegroup {
- name: "framework-hidl-jarjar",
- srcs: ["jarjar_rules_hidl.txt"],
+ name: "libvibrator_aidl",
+ srcs: [
+ "core/java/android/os/IExternalVibrationController.aidl",
+ "core/java/android/os/IExternalVibratorService.aidl",
+ ],
}
java_library {
@@ -910,6 +921,31 @@ aidl_interface {
api_dir: "aidl/networkstack",
}
+filegroup {
+ name: "framework-networkstack-shared-srcs",
+ srcs: [
+ // TODO: remove these annotations as soon as we can use andoid.support.annotations.*
+ "core/java/android/annotation/NonNull.java",
+ "core/java/android/annotation/Nullable.java",
+ "core/java/android/annotation/IntDef.java",
+ "core/java/android/annotation/IntRange.java",
+ "core/java/android/annotation/UnsupportedAppUsage.java",
+ "core/java/android/net/DhcpResults.java",
+ "core/java/android/util/LocalLog.java",
+ "core/java/com/android/internal/annotations/VisibleForTesting.java",
+ "core/java/com/android/internal/util/HexDump.java",
+ "core/java/com/android/internal/util/IndentingPrintWriter.java",
+ "core/java/com/android/internal/util/IState.java",
+ "core/java/com/android/internal/util/MessageUtils.java",
+ "core/java/com/android/internal/util/Preconditions.java",
+ "core/java/com/android/internal/util/RingBufferIndices.java",
+ "core/java/com/android/internal/util/State.java",
+ "core/java/com/android/internal/util/StateMachine.java",
+ "core/java/com/android/internal/util/WakeupMessage.java",
+ "core/java/android/net/shared/*.java",
+ ]
+}
+
// Build ext.jar
// ============================================================
java_library {
diff --git a/api/current.txt b/api/current.txt
index 2320a4ccde0f..361ee74becdd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5101,7 +5101,7 @@ package android.app {
}
public class KeyguardManager {
- method public android.content.Intent createConfirmDeviceCredentialIntent(CharSequence, CharSequence);
+ method @Deprecated public android.content.Intent createConfirmDeviceCredentialIntent(CharSequence, CharSequence);
method @Deprecated @RequiresPermission(android.Manifest.permission.DISABLE_KEYGUARD) public void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
method @Deprecated public boolean inKeyguardRestrictedInputMode();
method public boolean isDeviceLocked();
@@ -12512,6 +12512,7 @@ package android.database {
method public int getInt(int);
method public long getLong(int);
method public android.net.Uri getNotificationUri();
+ method public default java.util.List<android.net.Uri> getNotificationUris();
method public int getPosition();
method public short getShort(int);
method public String getString(int);
@@ -12535,6 +12536,7 @@ package android.database {
method public android.os.Bundle respond(android.os.Bundle);
method public void setExtras(android.os.Bundle);
method public void setNotificationUri(android.content.ContentResolver, android.net.Uri);
+ method public default void setNotificationUris(@NonNull android.content.ContentResolver, @NonNull java.util.List<android.net.Uri>);
method public void unregisterContentObserver(android.database.ContentObserver);
method public void unregisterDataSetObserver(android.database.DataSetObserver);
field public static final int FIELD_TYPE_BLOB = 4; // 0x4
@@ -13947,8 +13949,6 @@ package android.graphics {
@AnyThread public abstract class ColorSpace {
method @NonNull public static android.graphics.ColorSpace adapt(@NonNull android.graphics.ColorSpace, @NonNull @Size(min=2, max=3) float[]);
method @NonNull public static android.graphics.ColorSpace adapt(@NonNull android.graphics.ColorSpace, @NonNull @Size(min=2, max=3) float[], @NonNull android.graphics.ColorSpace.Adaptation);
- method @NonNull @Size(3) public static float[] cctToIlluminantdXyz(@IntRange(from=1) int);
- method @NonNull @Size(9) public static float[] chromaticAdaptation(@NonNull android.graphics.ColorSpace.Adaptation, @NonNull @Size(min=2, max=3) float[], @NonNull @Size(min=2, max=3) float[]);
method @NonNull public static android.graphics.ColorSpace.Connector connect(@NonNull android.graphics.ColorSpace, @NonNull android.graphics.ColorSpace);
method @NonNull public static android.graphics.ColorSpace.Connector connect(@NonNull android.graphics.ColorSpace, @NonNull android.graphics.ColorSpace, @NonNull android.graphics.ColorSpace.RenderIntent);
method @NonNull public static android.graphics.ColorSpace.Connector connect(@NonNull android.graphics.ColorSpace);
@@ -16498,6 +16498,7 @@ package android.hardware.biometrics {
ctor public BiometricPrompt.Builder(android.content.Context);
method public android.hardware.biometrics.BiometricPrompt build();
method public android.hardware.biometrics.BiometricPrompt.Builder setDescription(@NonNull CharSequence);
+ method public android.hardware.biometrics.BiometricPrompt.Builder setEnableFallback(boolean);
method public android.hardware.biometrics.BiometricPrompt.Builder setNegativeButton(@NonNull CharSequence, @NonNull java.util.concurrent.Executor, @NonNull android.content.DialogInterface.OnClickListener);
method public android.hardware.biometrics.BiometricPrompt.Builder setRequireConfirmation(boolean);
method public android.hardware.biometrics.BiometricPrompt.Builder setSubtitle(@NonNull CharSequence);
@@ -23522,6 +23523,8 @@ package android.media {
method public int setBufferSizeInFrames(int);
method public int setLoopPoints(int, int, int);
method public int setNotificationMarkerPosition(int);
+ method public void setOffloadDelayPadding(int, int);
+ method public void setOffloadEndOfStream();
method public int setPlaybackHeadPosition(int);
method public void setPlaybackParams(@NonNull android.media.PlaybackParams);
method public void setPlaybackPositionUpdateListener(android.media.AudioTrack.OnPlaybackPositionUpdateListener);
@@ -41409,9 +41412,9 @@ package android.service.notification {
method public int getUser();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
+ field public static final String KEY_CONTEXTUAL_ACTIONS = "key_contextual_actions";
field public static final String KEY_IMPORTANCE = "key_importance";
- field public static final String KEY_SMART_ACTIONS = "key_smart_actions";
- field public static final String KEY_SMART_REPLIES = "key_smart_replies";
+ field public static final String KEY_TEXT_REPLIES = "key_text_replies";
field public static final String KEY_USER_SENTIMENT = "key_user_sentiment";
}
@@ -44666,12 +44669,14 @@ package android.telephony {
public final class SmsManager {
method public String createAppSpecificSmsToken(android.app.PendingIntent);
+ method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
method public java.util.ArrayList<java.lang.String> divideMessage(String);
method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
method public android.os.Bundle getCarrierConfigValues();
method public static android.telephony.SmsManager getDefault();
method public static int getDefaultSmsSubscriptionId();
method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
+ method @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp(android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.SmsManager.FinancialSmsCallback);
method public int getSubscriptionId();
method public void injectSmsPdu(byte[], String, android.app.PendingIntent);
method public void sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
@@ -44734,6 +44739,11 @@ package android.telephony {
field public static final int STATUS_ON_ICC_UNSENT = 7; // 0x7
}
+ public abstract static class SmsManager.FinancialSmsCallback {
+ ctor public SmsManager.FinancialSmsCallback();
+ method public abstract void onFinancialSmsMessages(android.database.CursorWindow);
+ }
+
public class SmsMessage {
method public static int[] calculateLength(CharSequence, boolean);
method public static int[] calculateLength(String, boolean);
@@ -48572,6 +48582,7 @@ package android.view {
method public String getName();
method @Deprecated public int getOrientation();
method @Deprecated public int getPixelFormat();
+ method @Nullable public android.graphics.ColorSpace getPreferredWideGamutColorSpace();
method public long getPresentationDeadlineNanos();
method public void getRealMetrics(android.util.DisplayMetrics);
method public void getRealSize(android.graphics.Point);
@@ -55935,10 +55946,10 @@ package android.widget {
method @NonNull public android.widget.Magnifier.Builder setCornerRadius(@Px @FloatRange(from=0) float);
method @NonNull public android.widget.Magnifier.Builder setDefaultSourceToMagnifierOffset(@Px int, @Px int);
method @NonNull public android.widget.Magnifier.Builder setElevation(@Px @FloatRange(from=0) float);
+ method @NonNull public android.widget.Magnifier.Builder setInitialZoom(@FloatRange(from=0.0f) float);
method @NonNull public android.widget.Magnifier.Builder setOverlay(@Nullable android.graphics.drawable.Drawable);
method @NonNull public android.widget.Magnifier.Builder setSize(@Px @IntRange(from=0) int, @Px @IntRange(from=0) int);
method @NonNull public android.widget.Magnifier.Builder setSourceBounds(int, int, int, int);
- method @NonNull public android.widget.Magnifier.Builder setZoom(@FloatRange(from=0.0f) float);
}
public class MediaController extends android.widget.FrameLayout {
diff --git a/api/system-current.txt b/api/system-current.txt
index 30d42a232c8d..66e3642a8c05 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -508,11 +508,13 @@ package android.app {
method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getStatsMetadata() throws android.app.StatsManager.StatsUnavailableException;
method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void removeConfig(long) throws android.app.StatsManager.StatsUnavailableException;
method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean removeConfiguration(long);
+ method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void setActiveConfigsChangedOperation(@Nullable android.app.PendingIntent) throws android.app.StatsManager.StatsUnavailableException;
method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void setBroadcastSubscriber(android.app.PendingIntent, long, long) throws android.app.StatsManager.StatsUnavailableException;
method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setDataFetchOperation(long, android.app.PendingIntent);
method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void setFetchReportsOperation(android.app.PendingIntent, long) throws android.app.StatsManager.StatsUnavailableException;
field public static final String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
+ field public static final String EXTRA_STATS_ACTIVE_CONFIG_KEYS = "android.app.extra.STATS_ACTIVE_CONFIG_KEYS";
field public static final String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES = "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES";
field public static final String EXTRA_STATS_CONFIG_KEY = "android.app.extra.STATS_CONFIG_KEY";
field public static final String EXTRA_STATS_CONFIG_UID = "android.app.extra.STATS_CONFIG_UID";
@@ -1265,6 +1267,7 @@ package android.content {
field public static final String CONTEXTHUB_SERVICE = "contexthub";
field public static final String EUICC_CARD_SERVICE = "euicc_card";
field public static final String HDMI_CONTROL_SERVICE = "hdmi_control";
+ field public static final String NETD_SERVICE = "netd";
field public static final String NETWORK_SCORE_SERVICE = "network_score";
field public static final String OEM_LOCK_SERVICE = "oem_lock";
field public static final String PERMISSION_SERVICE = "permission";
@@ -1303,13 +1306,13 @@ package android.content {
field public static final String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS";
field @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public static final String ACTION_MANAGE_SPECIAL_APP_ACCESSES = "android.intent.action.MANAGE_SPECIAL_APP_ACCESSES";
field public static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
- field public static final String ACTION_PACKAGE_ROLLBACK_EXECUTED = "android.intent.action.PACKAGE_ROLLBACK_EXECUTED";
field public static final String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED";
field public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
field public static final String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE";
field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_APP_PERMISSION_USAGE = "android.intent.action.REVIEW_APP_PERMISSION_USAGE";
field public static final String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
field public static final String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE";
+ field public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED";
field public static final String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS";
field @Deprecated public static final String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
field public static final String ACTION_SPLIT_CONFIGURATION_CHANGED = "android.intent.action.SPLIT_CONFIGURATION_CHANGED";
@@ -1695,18 +1698,19 @@ package android.content.rollback {
public final class RollbackInfo implements android.os.Parcelable {
method public int describeContents();
+ method public java.util.List<android.content.rollback.PackageRollbackInfo> getPackages();
method public int getRollbackId();
+ method public int getSessionId();
+ method public boolean isStaged();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.rollback.RollbackInfo> CREATOR;
- field public final android.content.rollback.PackageRollbackInfo targetPackage;
}
public final class RollbackManager {
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void executeRollback(@NonNull android.content.rollback.RollbackInfo, @NonNull android.content.IntentSender);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull android.content.IntentSender);
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @Nullable public android.content.rollback.RollbackInfo getAvailableRollback(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<java.lang.String> getPackagesWithAvailableRollbacks();
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyExecutedRollbacks();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void reloadPersistedData();
}
@@ -4101,25 +4105,10 @@ package android.net {
method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
}
- public final class IpSecTransform implements java.lang.AutoCloseable {
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "android.permission.PACKET_KEEPALIVE_OFFLOAD"}) public void startNattKeepalive(@NonNull android.net.IpSecTransform.NattKeepaliveCallback, int, @NonNull android.os.Handler) throws java.io.IOException;
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "android.permission.PACKET_KEEPALIVE_OFFLOAD"}) public void stopNattKeepalive();
- }
-
public static class IpSecTransform.Builder {
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecTransform buildTunnelModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
}
- public static class IpSecTransform.NattKeepaliveCallback {
- ctor public IpSecTransform.NattKeepaliveCallback();
- method public void onError(int);
- method public void onStarted();
- method public void onStopped();
- field public static final int ERROR_HARDWARE_ERROR = 3; // 0x3
- field public static final int ERROR_HARDWARE_UNSUPPORTED = 2; // 0x2
- field public static final int ERROR_INVALID_NETWORK = 1; // 0x1
- }
-
public class LinkAddress implements android.os.Parcelable {
ctor public LinkAddress(java.net.InetAddress, int, int, int);
ctor public LinkAddress(java.net.InetAddress, int);
@@ -4249,6 +4238,24 @@ package android.net {
field public final android.net.RssiCurve rssiCurve;
}
+ public final class StaticIpConfiguration implements android.os.Parcelable {
+ ctor public StaticIpConfiguration();
+ ctor public StaticIpConfiguration(android.net.StaticIpConfiguration);
+ method public void addDnsServer(java.net.InetAddress);
+ method public void clear();
+ method public int describeContents();
+ method public java.util.List<java.net.InetAddress> getDnsServers();
+ method public String getDomains();
+ method public java.net.InetAddress getGateway();
+ method public android.net.LinkAddress getIpAddress();
+ method public java.util.List<android.net.RouteInfo> getRoutes(String);
+ method public void setDomains(String);
+ method public void setGateway(java.net.InetAddress);
+ method public void setIpAddress(android.net.LinkAddress);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
+ }
+
public class TrafficStats {
method public static void setThreadStatsTagApp();
method public static void setThreadStatsTagBackup();
@@ -4274,6 +4281,47 @@ package android.net {
}
+package android.net.apf {
+
+ public class ApfCapabilities {
+ ctor public ApfCapabilities(int, int, int);
+ method public boolean hasDataAccess();
+ field public final int apfPacketFormat;
+ field public final int apfVersionSupported;
+ field public final int maximumApfProgramSize;
+ }
+
+}
+
+package android.net.captiveportal {
+
+ public final class CaptivePortalProbeResult {
+ ctor public CaptivePortalProbeResult(int);
+ ctor public CaptivePortalProbeResult(int, String, String);
+ ctor public CaptivePortalProbeResult(int, String, String, android.net.captiveportal.CaptivePortalProbeSpec);
+ method public boolean isFailed();
+ method public boolean isPortal();
+ method public boolean isSuccessful();
+ field public static final android.net.captiveportal.CaptivePortalProbeResult FAILED;
+ field public static final int FAILED_CODE = 599; // 0x257
+ field public static final int PORTAL_CODE = 302; // 0x12e
+ field public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS;
+ field public static final int SUCCESS_CODE = 204; // 0xcc
+ field public final String detectUrl;
+ field @Nullable public final android.net.captiveportal.CaptivePortalProbeSpec probeSpec;
+ field public final String redirectUrl;
+ }
+
+ public abstract class CaptivePortalProbeSpec {
+ method public String getEncodedSpec();
+ method public abstract android.net.captiveportal.CaptivePortalProbeResult getResult(int, @Nullable String);
+ method public java.net.URL getUrl();
+ method public static java.util.Collection<android.net.captiveportal.CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(String);
+ method @Nullable public static android.net.captiveportal.CaptivePortalProbeSpec parseSpecOrNull(@Nullable String);
+ }
+
+}
+
package android.net.metrics {
public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
@@ -5060,6 +5108,36 @@ package android.os {
method public Object onTransactStarted(android.os.IBinder, int);
}
+ public class BugreportManager {
+ method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport();
+ method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
+ }
+
+ public abstract static class BugreportManager.BugreportCallback {
+ ctor public BugreportManager.BugreportCallback();
+ method public void onError(int);
+ method public void onFinished();
+ method public void onProgress(float);
+ field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1
+ field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2
+ field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4
+ field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3
+ }
+
+ public final class BugreportParams {
+ ctor public BugreportParams(@android.os.BugreportParams.BugreportMode int);
+ method public int getMode();
+ field public static final int BUGREPORT_MODE_FULL = 0; // 0x0
+ field public static final int BUGREPORT_MODE_INTERACTIVE = 1; // 0x1
+ field public static final int BUGREPORT_MODE_REMOTE = 2; // 0x2
+ field public static final int BUGREPORT_MODE_TELEPHONY = 4; // 0x4
+ field public static final int BUGREPORT_MODE_WEAR = 3; // 0x3
+ field public static final int BUGREPORT_MODE_WIFI = 5; // 0x5
+ }
+
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(prefix={"BUGREPORT_MODE_"}, value={android.os.BugreportParams.BUGREPORT_MODE_FULL, android.os.BugreportParams.BUGREPORT_MODE_INTERACTIVE, android.os.BugreportParams.BUGREPORT_MODE_REMOTE, android.os.BugreportParams.BUGREPORT_MODE_WEAR, android.os.BugreportParams.BUGREPORT_MODE_TELEPHONY, android.os.BugreportParams.BUGREPORT_MODE_WIFI}) public static @interface BugreportParams.BugreportMode {
+ }
+
public static class Build.VERSION {
field public static final String PREVIEW_SDK_FINGERPRINT;
}
@@ -5534,7 +5612,6 @@ package android.permissionpresenterservice {
method @Deprecated public final void attachBaseContext(android.content.Context);
method @Deprecated public final android.os.IBinder onBind(android.content.Intent);
method @Deprecated public abstract java.util.List<android.content.pm.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(@NonNull String);
- method @Deprecated public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String);
field @Deprecated public static final String SERVICE_INTERFACE = "android.permissionpresenterservice.RuntimePermissionPresenterService";
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 0f2ba12bd9ad..049e0025a59b 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6,6 +6,7 @@ package android {
field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
+ field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
@@ -866,6 +867,24 @@ package android.net {
field public static final int RTN_UNREACHABLE = 7; // 0x7
}
+ public final class StaticIpConfiguration implements android.os.Parcelable {
+ ctor public StaticIpConfiguration();
+ ctor public StaticIpConfiguration(android.net.StaticIpConfiguration);
+ method public void addDnsServer(java.net.InetAddress);
+ method public void clear();
+ method public int describeContents();
+ method public java.util.List<java.net.InetAddress> getDnsServers();
+ method public String getDomains();
+ method public java.net.InetAddress getGateway();
+ method public android.net.LinkAddress getIpAddress();
+ method public java.util.List<android.net.RouteInfo> getRoutes(String);
+ method public void setDomains(String);
+ method public void setGateway(java.net.InetAddress);
+ method public void setIpAddress(android.net.LinkAddress);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
+ }
+
public class TrafficStats {
method public static long getLoopbackRxBytes();
method public static long getLoopbackRxPackets();
@@ -875,6 +894,47 @@ package android.net {
}
+package android.net.apf {
+
+ public class ApfCapabilities {
+ ctor public ApfCapabilities(int, int, int);
+ method public boolean hasDataAccess();
+ field public final int apfPacketFormat;
+ field public final int apfVersionSupported;
+ field public final int maximumApfProgramSize;
+ }
+
+}
+
+package android.net.captiveportal {
+
+ public final class CaptivePortalProbeResult {
+ ctor public CaptivePortalProbeResult(int);
+ ctor public CaptivePortalProbeResult(int, String, String);
+ ctor public CaptivePortalProbeResult(int, String, String, android.net.captiveportal.CaptivePortalProbeSpec);
+ method public boolean isFailed();
+ method public boolean isPortal();
+ method public boolean isSuccessful();
+ field public static final android.net.captiveportal.CaptivePortalProbeResult FAILED;
+ field public static final int FAILED_CODE = 599; // 0x257
+ field public static final int PORTAL_CODE = 302; // 0x12e
+ field public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS;
+ field public static final int SUCCESS_CODE = 204; // 0xcc
+ field public final String detectUrl;
+ field @Nullable public final android.net.captiveportal.CaptivePortalProbeSpec probeSpec;
+ field public final String redirectUrl;
+ }
+
+ public abstract class CaptivePortalProbeSpec {
+ method public String getEncodedSpec();
+ method public abstract android.net.captiveportal.CaptivePortalProbeResult getResult(int, @Nullable String);
+ method public java.net.URL getUrl();
+ method public static java.util.Collection<android.net.captiveportal.CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(String);
+ method @Nullable public static android.net.captiveportal.CaptivePortalProbeSpec parseSpecOrNull(@Nullable String);
+ }
+
+}
+
package android.net.metrics {
public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
@@ -1053,6 +1113,10 @@ package android.os {
method public static java.io.File getStorageDirectory();
}
+ public class FileUtils {
+ method public static boolean contains(java.io.File, java.io.File);
+ }
+
public abstract class HwBinder implements android.os.IHwBinder {
ctor public HwBinder();
method public static final void configureRpcThreadpool(long, boolean);
@@ -1218,6 +1282,10 @@ package android.os {
method public boolean hasSingleFileDescriptor();
}
+ public class ParcelFileDescriptor implements java.io.Closeable android.os.Parcelable {
+ method public static java.io.File getFile(java.io.FileDescriptor) throws java.io.IOException;
+ }
+
public final class PowerManager {
method @RequiresPermission("android.permission.POWER_SAVER") public int getPowerSaveMode();
method @RequiresPermission("android.permission.POWER_SAVER") public boolean setDynamicPowerSavings(boolean, int);
@@ -1485,17 +1553,37 @@ package android.print {
package android.provider {
+ public static final class CalendarContract.Calendars implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.SyncColumns {
+ field public static final String[] SYNC_WRITABLE_COLUMNS;
+ }
+
+ public static final class CalendarContract.Events implements android.provider.BaseColumns android.provider.CalendarContract.CalendarColumns android.provider.CalendarContract.EventsColumns android.provider.CalendarContract.SyncColumns {
+ field public static final String[] SYNC_WRITABLE_COLUMNS;
+ }
+
+ public final class ContactsContract {
+ field public static final String HIDDEN_COLUMN_PREFIX = "x_";
+ }
+
public static final class ContactsContract.CommonDataKinds.Phone implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
field public static final android.net.Uri ENTERPRISE_CONTENT_URI;
}
+ public static final class ContactsContract.PinnedPositions {
+ field public static final String UNDEMOTE_METHOD = "undemote";
+ }
+
public static final class ContactsContract.RawContactsEntity implements android.provider.BaseColumns android.provider.ContactsContract.DataColumns android.provider.ContactsContract.RawContactsColumns {
field public static final android.net.Uri CORP_CONTENT_URI;
}
public final class MediaStore {
- method @RequiresPermission("android.permission.CLEAR_APP_USER_DATA") public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
- method @RequiresPermission("android.permission.CLEAR_APP_USER_DATA") public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
+ method @NonNull public static java.io.File getVolumePath(@NonNull String) throws java.io.FileNotFoundException;
+ method @NonNull public static java.util.Collection<java.io.File> getVolumeScanPaths(@NonNull String) throws java.io.FileNotFoundException;
+ field public static final String SCAN_FILE_CALL = "scan_file";
+ field public static final String SCAN_VOLUME_CALL = "scan_volume";
}
public final class Settings {
@@ -1555,6 +1643,10 @@ package android.provider {
field public static final String SMS_CARRIER_PROVISION_ACTION = "android.provider.Telephony.SMS_CARRIER_PROVISION";
}
+ public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
+ field public static final String _DATA = "_data";
+ }
+
}
package android.security {
@@ -1829,10 +1921,15 @@ package android.telephony {
}
public class TelephonyManager {
+ method public int checkCarrierPrivilegesForPackage(String);
method public int getCarrierIdListVersion();
method public boolean isRttSupported();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
method public void setCarrierTestOverride(String, String, String, String, String, String, String);
+ 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
+ field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
+ field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
field public static final int UNKNOWN_CARRIER_ID_LIST_VERSION = -1; // 0xffffffff
}
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 9c320d3e2b03..b26c713877db 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -989,6 +989,25 @@ Status StatsService::setDataFetchOperation(int64_t key,
return Status::ok();
}
+Status StatsService::setActiveConfigsChangedOperation(const sp<android::IBinder>& intentSender,
+ const String16& packageName,
+ vector<int64_t>* output) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
+ IPCThreadState* ipc = IPCThreadState::self();
+ mConfigManager->SetActiveConfigsChangedReceiver(ipc->getCallingUid(), intentSender);
+ //TODO: Return the list of configs that are already active
+ return Status::ok();
+}
+
+Status StatsService::removeActiveConfigsChangedOperation(const String16& packageName) {
+ ENFORCE_DUMP_AND_USAGE_STATS(packageName);
+
+ IPCThreadState* ipc = IPCThreadState::self();
+ mConfigManager->RemoveActiveConfigsChangedReceiver(ipc->getCallingUid());
+ return Status::ok();
+}
+
Status StatsService::removeConfiguration(int64_t key, const String16& packageName) {
ENFORCE_DUMP_AND_USAGE_STATS(packageName);
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index fe0504fc034f..cdff50fcb62e 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -132,6 +132,17 @@ public:
const String16& packageName) override;
/**
+ * Binder call to let clients register the active configs changed operation.
+ */
+ virtual Status setActiveConfigsChangedOperation(const sp<android::IBinder>& intentSender,
+ const String16& packageName,
+ vector<int64_t>* output) override;
+
+ /**
+ * Binder call to remove the active configs changed operation for the specified package..
+ */
+ virtual Status removeActiveConfigsChangedOperation(const String16& packageName) override;
+ /**
* Binder call to allow clients to remove the specified configuration.
*/
virtual Status removeConfiguration(int64_t key,
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 1a0a98352051..8e56bef6856e 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -28,6 +28,7 @@ import "frameworks/base/core/proto/android/bluetooth/enums.proto";
import "frameworks/base/core/proto/android/bluetooth/hci/enums.proto";
import "frameworks/base/core/proto/android/bluetooth/hfp/enums.proto";
import "frameworks/base/core/proto/android/debug/enums.proto";
+import "frameworks/base/core/proto/android/hardware/biometrics/enums.proto";
import "frameworks/base/core/proto/android/net/networkcapabilities.proto";
import "frameworks/base/core/proto/android/os/enums.proto";
import "frameworks/base/core/proto/android/server/connectivity/data_stall_event.proto";
@@ -146,9 +147,9 @@ message Atom {
VibratorStateChanged vibrator_state_changed = 84;
DeferredJobStatsReported deferred_job_stats_reported = 85;
ThermalThrottlingStateChanged thermal_throttling = 86;
- FingerprintAcquired fingerprint_acquired = 87;
- FingerprintAuthenticated fingerprint_authenticated = 88;
- FingerprintErrorOccurred fingerprint_error_occurred = 89;
+ BiometricAcquired biometric_acquired = 87;
+ BiometricAuthenticated biometric_authenticated = 88;
+ BiometricErrorOccurred biometric_error_occurred = 89;
Notification notification = 90;
BatteryHealthSnapshot battery_health_snapshot = 91;
SlowIo slow_io = 92;
@@ -163,7 +164,7 @@ message Atom {
// Consider removing this if it becomes a problem
ServiceStateChanged service_state_changed = 99;
ServiceLaunchReported service_launch_reported = 100;
- PhenotypeFlagStateChanged phenotype_flag_state_changed = 101;
+ FlagFlipUpdateOccurred flag_flip_update_occurred = 101;
BinaryPushStateChanged binary_push_state_changed = 102;
DevicePolicyEvent device_policy_event = 103;
DocsUIFileOperationCanceledReported docs_ui_file_op_canceled = 104;
@@ -209,6 +210,9 @@ message Atom {
AdbConnectionChanged adb_connection_changed = 144;
SpeechDspStatReported speech_dsp_stat_reported = 145;
UsbContaminantReported usb_contaminant_reported = 146;
+ WatchdogRollbackOccurred watchdog_rollback_occurred = 147;
+ BiometricHalDeathReported biometric_hal_death_reported = 148;
+ BubbleUIChanged bubble_ui_changed = 149;
}
// Pulled events will start at field 10000.
@@ -245,7 +249,7 @@ message Atom {
CategorySize category_size = 10028;
ProcStats proc_stats = 10029;
BatteryVoltage battery_voltage = 10030;
- NumFingerprints num_fingerprints = 10031;
+ NumBiometricsEnrolled num_fingerprints_enrolled = 10031;
DiskIo disk_io = 10032;
PowerProfile power_profile = 10033;
ProcStatsPkgProc proc_stats_pkg_proc = 10034;
@@ -262,6 +266,7 @@ message Atom {
BatteryCycleCount battery_cycle_count = 10045;
DebugElapsedClock debug_elapsed_clock = 10046;
DebugFailingElapsedClock debug_failing_elapsed_clock = 10047;
+ NumBiometricsEnrolled num_faces_enrolled = 10048;
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -1485,6 +1490,25 @@ message BluetoothLinkLayerConnectionEvent {
optional android.bluetooth.hci.StatusEnum reason_code = 9;
}
+/**
+ * Logs when a module is rolled back by Watchdog.
+ *
+ * Logged from: Rollback Manager
+ */
+message WatchdogRollbackOccurred {
+ enum RollbackType {
+ UNKNOWN = 0;
+ ROLLBACK_INITIATE = 1;
+ ROLLBACK_SUCCESS = 2;
+ ROLLBACK_FAILURE = 3;
+ }
+ optional RollbackType rollback_type = 1;
+
+ optional string package_name = 2;
+
+ optional int32 package_version_code = 3;
+}
+
/**
* Logs when something is plugged into or removed from the USB-C connector.
@@ -2353,58 +2377,95 @@ message GenericAtom {
}
/**
- * Logs when a fingerprint acquire event occurs.
+ * Logs when a biometric acquire event occurs.
*
* Logged from:
- * frameworks/base/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+ * frameworks/base/services/core/java/com/android/server/biometrics
*/
-message FingerprintAcquired {
- // The associated user. Eg: 0 for owners, 10+ for others.
- // Defined in android/os/UserHandle.java
- optional int32 user = 1;
- // If this acquire is for a crypto fingerprint.
- // e.g. Secure purchases, unlock password storage.
- optional bool is_crypto = 2;
+message BiometricAcquired {
+ // Biometric modality that was acquired.
+ optional android.hardware.biometrics.ModalityEnum modality = 1;
+ // The associated user. Eg: 0 for owners, 10+ for others. Defined in android/os/UserHandle.java.
+ optional int32 user = 2;
+ // If this acquire is for a crypto operation. e.g. Secure purchases, unlock password storage.
+ optional bool is_crypto = 3;
+ // Action that the device is performing. Acquired messages are only expected for enroll and
+ // authenticate. Other actions may indicate an error.
+ optional android.hardware.biometrics.ActionEnum action = 4;
+ // The client that this acquisition was received for.
+ optional android.hardware.biometrics.ClientEnum client = 5;
+ // Acquired constants, e.g. ACQUIRED_GOOD. See constants defined by <Biometric>Manager.
+ optional int32 acquire_info = 6;
+ // Vendor-specific acquire info. Valid only if acquire_info == ACQUIRED_VENDOR.
+ optional int32 acquire_info_vendor = 7;
}
/**
- * Logs when a fingerprint authentication event occurs.
+ * Logs when a biometric authentication event occurs.
*
* Logged from:
- * frameworks/base/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
- */
-message FingerprintAuthenticated {
- // The associated user. Eg: 0 for owners, 10+ for others.
- // Defined in android/os/UserHandle.java
- optional int32 user = 1;
- // If this authentication is for a crypto fingerprint.
- // e.g. Secure purchases, unlock password storage.
- optional bool is_crypto = 2;
- // Whether or not this authentication was successful.
- optional bool is_authenticated = 3;
+ * frameworks/base/services/core/java/com/android/server/biometrics
+ */
+message BiometricAuthenticated {
+ // Biometric modality that was used.
+ optional android.hardware.biometrics.ModalityEnum modality = 1;
+ // The associated user. Eg: 0 for owners, 10+ for others. Defined in android/os/UserHandle.java
+ optional int32 user = 2;
+ // If this authentication is for a crypto operation. e.g. Secure purchases, unlock password
+ // storage.
+ optional bool is_crypto = 3;
+ // The client that this acquisition was received for.
+ optional android.hardware.biometrics.ClientEnum client = 4;
+
+ enum State {
+ UNKNOWN = 0;
+ REJECTED = 1;
+ PENDING_CONFIRMATION = 2;
+ CONFIRMED = 3;
+ }
+
+ // State of the current auth attempt.
+ optional State state = 5;
+ // Time it took to authenticate. For BiometricPrompt where setRequireConfirmation(false) is
+ // specified and supported by the biometric modality, this is from the first ACQUIRED_GOOD to
+ // AUTHENTICATED. for setRequireConfirmation(true), this is from PENDING_CONFIRMATION to
+ // CONFIRMED.
+ optional int64 latency_millis = 6;
}
/**
- * Logs when a fingerprint error occurs.
+ * Logs when a biometric error occurs.
*
* Logged from:
- * frameworks/base/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+ * frameworks/base/services/core/java/com/android/server/biometrics
+ */
+message BiometricErrorOccurred {
+ // Biometric modality that was used.
+ optional android.hardware.biometrics.ModalityEnum modality = 1;
+ // The associated user. Eg: 0 for owners, 10+ for others. Defined in android/os/UserHandle.java
+ optional int32 user = 2;
+ // If this error is for a crypto operation. e.g. Secure purchases, unlock password storage.
+ optional bool is_crypto = 3;
+ // Action that the device is performing.
+ optional android.hardware.biometrics.ActionEnum action = 4;
+ // The client that this acquisition was received for.
+ optional android.hardware.biometrics.ClientEnum client = 5;
+ // Error constants. See constants defined by <Biometric>Manager. Enums won't work since errors
+ // are unique to modality.
+ optional int32 error_info = 6;
+ // Vendor-specific error info. Valid only if acquire_info == ACQUIRED_VENDOR. These are defined
+ // by the vendor and not specified by the HIDL interface.
+ optional int32 error_info_vendor = 7;
+}
+
+/**
+ * Logs when a biometric HAL has crashed.
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/biometrics
*/
-message FingerprintErrorOccurred {
- // The associated user. Eg: 0 for owners, 10+ for others.
- // Defined in android/os/UserHandle.java
- optional int32 user = 1;
- // If this error is for a crypto fingerprint.
- // e.g. Secure purchases, unlock password storage.
- optional bool is_crypto = 2;
-
- enum Error {
- UNKNOWN = 0;
- LOCKOUT = 1;
- PERMANENT_LOCKOUT = 2;
- }
- // The type of error.
- optional Error error = 3;
+message BiometricHalDeathReported {
+ // Biometric modality.
+ optional android.hardware.biometrics.ModalityEnum modality = 1;
}
message Notification {
@@ -2478,18 +2539,14 @@ message Notification {
}
/*
- * Logs when a flag flip state changes.
- * Logged in P/h.
+ * Logs when a flag flip update occurrs. Used for mainline modules that update via flag flips.
*/
-message PhenotypeFlagStateChanged {
- // Mendel configuration name.
- optional string mendel_config_name = 1;
- // State
- enum State {
- STATE_UNKNOWN = 0;
- COMMITTED = 1;
- }
- optional State state = 2;
+message FlagFlipUpdateOccurred {
+ // If the event is from a flag config package, specify the package name.
+ optional string flag_flip_package_name = 1;
+
+ // The order id of the package
+ optional int64 order_id = 2;
}
/*
@@ -3351,14 +3408,14 @@ message DiskIo {
/**
* Pulls the number of fingerprints for each user.
*
- * Pulled from StatsCompanionService, which queries FingerprintManager.
+ * Pulled from StatsCompanionService, which queries <Biometric>Manager.
*/
-message NumFingerprints {
+message NumBiometricsEnrolled {
// The associated user. Eg: 0 for owners, 10+ for others.
// Defined in android/os/UserHandle.java
optional int32 user = 1;
// Number of fingerprints registered to that user.
- optional int32 num_fingerprints = 2;
+ optional int32 num_enrolled = 2;
}
message AggStats {
@@ -4595,3 +4652,50 @@ message DebugFailingElapsedClock {
// Diff between current elapsed time and elapsed time from previous pull.
optional int64 elapsed_clock_diff_millis = 4;
}
+
+/** Logs System UI bubbles event changed.
+ *
+ * Logged from:
+ * frameworks/base/packages/SystemUI/src/com/android/systemui/bubbles
+ */
+message BubbleUIChanged {
+
+ // The app package that is posting the bubble.
+ optional string package_name = 1;
+
+ // The notification channel that is posting the bubble.
+ optional string notification_channel = 2;
+
+ // The notification id associated with the posted bubble.
+ optional int32 notification_id = 3;
+
+ // The position of the bubble within the bubble stack.
+ optional int32 position = 4;
+
+ // The total number of bubbles within the bubble stack.
+ optional int32 total_number = 5;
+
+ // User interactions with the bubble.
+ enum Action {
+ UNKNOWN = 0;
+ POSTED = 1;
+ UPDATED = 2;
+ EXPANDED = 3;
+ COLLAPSED = 4;
+ DISMISSED = 5;
+ STACK_DISMISSED = 6;
+ STACK_MOVED = 7;
+ HEADER_GO_TO_APP = 8;
+ HEADER_GO_TO_SETTINGS = 9;
+ PERMISSION_OPT_IN = 10;
+ PERMISSION_OPT_OUT = 11;
+ PERMISSION_IGNORED = 12;
+ SWIPE_LEFT = 13;
+ SWIPE_RIGHT = 14;
+ }
+ optional Action action = 6;
+
+ // Normalized screen position of the bubble stack. The range is between 0 and 1.
+ optional float normalized_x_position = 7;
+ optional float normalized_y_position = 8;
+}
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 5fea90b61c80..aa22333ab26c 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -128,6 +128,17 @@ void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) {
mConfigReceivers.erase(key);
}
+void ConfigManager::SetActiveConfigsChangedReceiver(const int uid,
+ const sp<IBinder>& intentSender) {
+ lock_guard<mutex> lock(mMutex);
+ mActiveConfigsChangedReceivers[uid] = intentSender;
+}
+
+void ConfigManager::RemoveActiveConfigsChangedReceiver(const int uid) {
+ lock_guard<mutex> lock(mMutex);
+ mActiveConfigsChangedReceivers.erase(uid);
+}
+
void ConfigManager::RemoveConfig(const ConfigKey& key) {
vector<sp<ConfigListener>> broadcastList;
{
@@ -181,6 +192,11 @@ void ConfigManager::RemoveConfigs(int uid) {
mConfigReceivers.erase(*it);
}
+ auto itActiveConfigsChangedReceiver = mActiveConfigsChangedReceivers.find(uid);
+ if (itActiveConfigsChangedReceiver != mActiveConfigsChangedReceivers.end()) {
+ mActiveConfigsChangedReceivers.erase(itActiveConfigsChangedReceiver);
+ }
+
mConfigs.erase(uidIt);
for (const sp<ConfigListener>& listener : mListeners) {
@@ -213,6 +229,7 @@ void ConfigManager::RemoveAllConfigs() {
}
mConfigReceivers.clear();
+ mActiveConfigsChangedReceivers.clear();
for (const sp<ConfigListener>& listener : mListeners) {
broadcastList.push_back(listener);
}
@@ -250,6 +267,17 @@ const sp<android::IBinder> ConfigManager::GetConfigReceiver(const ConfigKey& key
}
}
+const sp<android::IBinder> ConfigManager::GetActiveConfigsChangedReceiver(const int uid) const {
+ lock_guard<mutex> lock(mMutex);
+
+ auto it = mActiveConfigsChangedReceivers.find(uid);
+ if (it == mActiveConfigsChangedReceivers.end()) {
+ return nullptr;
+ } else {
+ return it->second;
+ }
+}
+
void ConfigManager::Dump(FILE* out) {
lock_guard<mutex> lock(mMutex);
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index 122e669057b0..c064a519f597 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -82,6 +82,23 @@ public:
void RemoveConfigReceiver(const ConfigKey& key);
/**
+ * Sets the broadcast receiver that is notified whenever the list of active configs
+ * changes for this uid.
+ */
+ void SetActiveConfigsChangedReceiver(const int uid, const sp<IBinder>& intentSender);
+
+ /**
+ * Returns the broadcast receiver for active configs changed for this uid.
+ */
+
+ const sp<IBinder> GetActiveConfigsChangedReceiver(const int uid) const;
+
+ /**
+ * Erase any active configs changed broadcast receiver associated with this uid.
+ */
+ void RemoveActiveConfigsChangedReceiver(const int uid);
+
+ /**
* A configuration was removed.
*
* Reports this to listeners.
@@ -130,6 +147,12 @@ private:
std::map<ConfigKey, sp<android::IBinder>> mConfigReceivers;
/**
+ * Each uid can be subscribed by up to one receiver to notify that the list of active configs
+ * for this uid has changed. The receiver is specified as IBinder from PendingIntent.
+ */
+ std::map<int, sp<android::IBinder>> mActiveConfigsChangedReceivers;
+
+ /**
* The ConfigListeners that will be told about changes.
*/
std::vector<sp<ConfigListener>> mListeners;
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 4585a09176ce..ba7bcc437d74 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -175,8 +175,8 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = {
{android::util::CATEGORY_SIZE,
{.puller = new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}},
// Number of fingerprints registered to each user.
- {android::util::NUM_FINGERPRINTS,
- {.puller = new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS)}},
+ {android::util::NUM_FINGERPRINTS_ENROLLED,
+ {.puller = new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS_ENROLLED)}},
// ProcStats.
{android::util::PROC_STATS,
{.puller = new StatsCompanionServicePuller(android::util::PROC_STATS)}},
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index ee2fe8f5750f..8e7a58b40d0c 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -901,7 +901,6 @@ Landroid/os/ParcelableParcel;->getClassLoader()Ljava/lang/ClassLoader;
Landroid/os/ParcelableParcel;->getParcel()Landroid/os/Parcel;
Landroid/os/ParcelFileDescriptor;-><init>(Ljava/io/FileDescriptor;)V
Landroid/os/ParcelFileDescriptor;->fromData([BLjava/lang/String;)Landroid/os/ParcelFileDescriptor;
-Landroid/os/ParcelFileDescriptor;->getFile(Ljava/io/FileDescriptor;)Ljava/io/File;
Landroid/os/ParcelFileDescriptor;->seekTo(J)J
Landroid/os/PerformanceCollector;-><init>()V
Landroid/os/PerformanceCollector;->beginSnapshot(Ljava/lang/String;)V
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 181accea2e6a..f522d71afd08 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -29,6 +29,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.hardware.biometrics.BiometricPrompt;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -87,6 +88,12 @@ public class KeyguardManager {
"android.app.action.CONFIRM_FRP_CREDENTIAL";
/**
+ * @hide
+ */
+ public static final String EXTRA_BIOMETRIC_PROMPT_BUNDLE =
+ "android.app.extra.BIOMETRIC_PROMPT_BUNDLE";
+
+ /**
* A CharSequence dialog title to show to the user when used with a
* {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
* @hide
@@ -101,12 +108,6 @@ public class KeyguardManager {
public static final String EXTRA_DESCRIPTION = "android.app.extra.DESCRIPTION";
/**
- * A boolean value to forward to {@link android.hardware.biometrics.BiometricPrompt}.
- * @hide
- */
- public static final String EXTRA_USE_IMPLICIT = "android.app.extra.USE_IMPLICIT";
-
- /**
* A CharSequence description to show to the user on the alternate button when used with
* {@link #ACTION_CONFIRM_FRP_CREDENTIAL}.
* @hide
@@ -124,44 +125,23 @@ public class KeyguardManager {
public static final int RESULT_ALTERNATE = 1;
/**
- * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
- * for the current user of the device. The caller is expected to launch this activity using
- * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
+ * @deprecated see {@link BiometricPrompt.Builder#setEnableFallback(boolean)}
+ *
+ * Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics
+ * if enrolled) for the current user of the device. The caller is expected to launch this
+ * activity using {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
* {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
*
- * @param title Title to be shown on the dialog.
- * @param description Description to be shown on the dialog.
* @return the intent for launching the activity or null if no password is required.
**/
+ @Deprecated
@RequiresFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN)
- public Intent createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description) {
- return createConfirmDeviceCredentialIntent(title, description, false /* useImplicit */);
- }
-
- /**
- * Get an intent to prompt the user to confirm credentials (pin, pattern or password)
- * for the current user of the device. The caller is expected to launch this activity using
- * {@link android.app.Activity#startActivityForResult(Intent, int)} and check for
- * {@link android.app.Activity#RESULT_OK} if the user successfully completes the challenge.
- *
- * @param title Title to be shown on the dialog.
- * @param description Description to be shown on the dialog.
- * @param useImplicit If useImplicit is set to true, ConfirmDeviceCredentials will invoke
- * {@link android.hardware.biometrics.BiometricPrompt} with
- * {@link android.hardware.biometrics.BiometricPrompt.Builder#setRequireConfirmation(
- * boolean)} set to false.
- * @return the intent for launching the activity or null if no password is required.
- * @hide
- */
- public Intent createConfirmDeviceCredentialIntent(CharSequence title, CharSequence description,
- boolean useImplicit) {
- if (!isDeviceSecure()) {
- return null;
- }
+ public Intent createConfirmDeviceCredentialIntent(CharSequence title,
+ CharSequence description) {
+ if (!isDeviceSecure()) return null;
Intent intent = new Intent(ACTION_CONFIRM_DEVICE_CREDENTIAL);
intent.putExtra(EXTRA_TITLE, title);
intent.putExtra(EXTRA_DESCRIPTION, description);
- intent.putExtra(EXTRA_USE_IMPLICIT, useImplicit);
// explicitly set the package for security
intent.setPackage(getSettingsPackageForIntent(intent));
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 9dcd1228522b..9b66c928abc0 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -73,6 +73,11 @@ public final class StatsManager {
*/
public static final String EXTRA_STATS_DIMENSIONS_VALUE =
"android.app.extra.STATS_DIMENSIONS_VALUE";
+ /**
+ * Long array extra of the active configs for the uid that added those configs.
+ */
+ public static final String EXTRA_STATS_ACTIVE_CONFIG_KEYS =
+ "android.app.extra.STATS_ACTIVE_CONFIG_KEYS";
/**
* Broadcast Action: Statsd has started.
@@ -274,6 +279,43 @@ public final class StatsManager {
}
}
+ /**
+ * Registers the operation that is called whenever there is a change in which configs are
+ * active. This must be called each time statsd starts. This operation allows
+ * statsd to inform clients that they should pull data of the configs that are currently
+ * active. The activeConfigsChangedOperation should set periodic alarms to pull data of configs
+ * that are active and stop pulling data of configs that are no longer active.
+ *
+ * @param pendingIntent the PendingIntent to use when broadcasting info to the subscriber
+ * associated with the given subscriberId. May be null, in which case
+ * it removes any associated pending intent for this client.
+ * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
+ */
+ @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
+ public void setActiveConfigsChangedOperation(@Nullable PendingIntent pendingIntent)
+ throws StatsUnavailableException {
+ synchronized (this) {
+ try {
+ IStatsManager service = getIStatsManagerLocked();
+ if (pendingIntent == null) {
+ service.removeActiveConfigsChangedOperation(mContext.getOpPackageName());
+ } else {
+ // Extracts IIntentSender from the PendingIntent and turns it into an IBinder.
+ IBinder intentSender = pendingIntent.getTarget().asBinder();
+ service.setActiveConfigsChangedOperation(intentSender,
+ mContext.getOpPackageName());
+ }
+
+ } catch (RemoteException e) {
+ Slog.e(TAG,
+ "Failed to connect to statsd when registering active configs listener.");
+ throw new StatsUnavailableException("could not connect", e);
+ } catch (SecurityException e) {
+ throw new StatsUnavailableException(e.getMessage(), e);
+ }
+ }
+ }
+
// TODO: Temporary for backwards compatibility. Remove.
/**
* @deprecated Use {@link #setFetchReportsOperation(PendingIntent, long)}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 2dc225af6482..ee13164d7564 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -102,6 +102,7 @@ import android.net.IConnectivityManager;
import android.net.IEthernetManager;
import android.net.IIpMemoryStore;
import android.net.IIpSecService;
+import android.net.INetd;
import android.net.INetworkPolicyManager;
import android.net.IpMemoryStore;
import android.net.IpSecManager;
@@ -328,6 +329,14 @@ final class SystemServiceRegistry {
return new ConnectivityManager(context, service);
}});
+ registerService(Context.NETD_SERVICE, INetd.class, new StaticServiceFetcher<INetd>() {
+ @Override
+ public INetd createService() throws ServiceNotFoundException {
+ return INetd.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.NETD_SERVICE));
+ }
+ });
+
registerService(Context.NETWORK_STACK_SERVICE, NetworkStack.class,
new StaticServiceFetcher<NetworkStack>() {
@Override
diff --git a/core/java/android/app/role/IRoleManager.aidl b/core/java/android/app/role/IRoleManager.aidl
index 2964fbc0084b..cf62e8d625db 100644
--- a/core/java/android/app/role/IRoleManager.aidl
+++ b/core/java/android/app/role/IRoleManager.aidl
@@ -18,6 +18,8 @@ package android.app.role;
import android.app.role.IOnRoleHoldersChangedListener;
import android.app.role.IRoleManagerCallback;
+import android.os.Bundle;
+import android.telephony.IFinancialSmsCallback;
/**
* @hide
@@ -52,4 +54,8 @@ interface IRoleManager {
List<String> getHeldRolesFromController(in String packageName);
String getDefaultSmsPackage(int userId);
+ /**
+ * Get filtered SMS messages for financial app.
+ */
+ void getSmsMessagesForFinancialApp(in String callingPkg, in Bundle params, in IFinancialSmsCallback callback);
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 6704a45fb07a..47a4a2dca73d 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -87,6 +87,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* <p>For more information about using a ContentResolver with content providers, read the
* <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
* developer guide.</p>
+ * </div>
*/
public abstract class ContentResolver implements ContentInterface {
/**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 280f1ac9c067..87f9e464cdc2 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3637,6 +3637,16 @@ public abstract class Context {
/**
* Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.net.INetd} for communicating with the network stack
+ * @hide
+ * @see #getSystemService(String)
+ * @hide
+ */
+ @SystemApi
+ public static final String NETD_SERVICE = "netd";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve a
* {@link NetworkStack} for communicating with the network stack
* @hide
* @see #getSystemService(String)
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9e7aaf652a4d..22f73dbd4644 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2375,8 +2375,7 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_PACKAGE_ENABLE_ROLLBACK =
"android.intent.action.PACKAGE_ENABLE_ROLLBACK";
/**
- * Broadcast Action: An existing version of an application package has been
- * rolled back to a previous version.
+ * Broadcast Action: A rollback has been committed.
*
* <p class="note">This is a protected intent that can only be sent
* by the system.
@@ -2385,8 +2384,8 @@ public class Intent implements Parcelable, Cloneable {
*/
@SystemApi
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_PACKAGE_ROLLBACK_EXECUTED =
- "android.intent.action.PACKAGE_ROLLBACK_EXECUTED";
+ public static final String ACTION_ROLLBACK_COMMITTED =
+ "android.intent.action.ROLLBACK_COMMITTED";
/**
* @hide
* Broadcast Action: Ask system services if there is any reason to
diff --git a/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl b/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
index 2faf3adb34b6..4f4c34b88cbd 100644
--- a/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
+++ b/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
@@ -27,5 +27,4 @@ import android.os.RemoteCallback;
*/
oneway interface IRuntimePermissionPresenter {
void getAppPermissions(String packageName, in RemoteCallback callback);
- void revokeRuntimePermission(String packageName, String permissionName);
}
diff --git a/core/java/android/content/rollback/IRollbackManager.aidl b/core/java/android/content/rollback/IRollbackManager.aidl
index 420bcb69e0c4..226d76abc01c 100644
--- a/core/java/android/content/rollback/IRollbackManager.aidl
+++ b/core/java/android/content/rollback/IRollbackManager.aidl
@@ -17,20 +17,16 @@
package android.content.rollback;
import android.content.pm.ParceledListSlice;
-import android.content.pm.StringParceledListSlice;
import android.content.rollback.RollbackInfo;
import android.content.IntentSender;
/** {@hide} */
interface IRollbackManager {
- RollbackInfo getAvailableRollback(String packageName);
-
- StringParceledListSlice getPackagesWithAvailableRollbacks();
-
+ ParceledListSlice getAvailableRollbacks();
ParceledListSlice getRecentlyExecutedRollbacks();
- void executeRollback(in RollbackInfo rollback, String callerPackageName,
+ void commitRollback(int rollbackId, String callerPackageName,
in IntentSender statusReceiver);
// Exposed for use from the system server only. Callback from the package
diff --git a/core/java/android/content/rollback/RollbackInfo.java b/core/java/android/content/rollback/RollbackInfo.java
index 0803a7c1d651..812f995675fc 100644
--- a/core/java/android/content/rollback/RollbackInfo.java
+++ b/core/java/android/content/rollback/RollbackInfo.java
@@ -17,9 +17,12 @@
package android.content.rollback;
import android.annotation.SystemApi;
+import android.content.pm.PackageInstaller;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.List;
+
/**
* Information about a set of packages that can be, or already have been
* rolled back together.
@@ -34,25 +37,17 @@ public final class RollbackInfo implements Parcelable {
*/
private final int mRollbackId;
- /**
- * The package that needs to be rolled back.
- */
- public final PackageRollbackInfo targetPackage;
-
- // TODO: Add a list of additional packages rolled back due to atomic
- // install dependencies when rollback of atomic installs is supported.
- // TODO: Add a flag to indicate if reboot is required, when rollback of
- // staged installs is supported.
+ private final List<PackageRollbackInfo> mPackages;
/** @hide */
- public RollbackInfo(int rollbackId, PackageRollbackInfo targetPackage) {
+ public RollbackInfo(int rollbackId, List<PackageRollbackInfo> packages) {
this.mRollbackId = rollbackId;
- this.targetPackage = targetPackage;
+ this.mPackages = packages;
}
private RollbackInfo(Parcel in) {
mRollbackId = in.readInt();
- targetPackage = PackageRollbackInfo.CREATOR.createFromParcel(in);
+ mPackages = in.createTypedArrayList(PackageRollbackInfo.CREATOR);
}
/**
@@ -62,6 +57,31 @@ public final class RollbackInfo implements Parcelable {
return mRollbackId;
}
+ /**
+ * Returns the list of package that are rolled back.
+ */
+ public List<PackageRollbackInfo> getPackages() {
+ return mPackages;
+ }
+
+ /**
+ * Returns true if this rollback requires reboot to take effect after
+ * being committed.
+ */
+ public boolean isStaged() {
+ // TODO: Support rollback of staged installs.
+ return false;
+ }
+
+ /**
+ * Returns the session ID for the committed rollback for staged rollbacks.
+ * Only applicable for rollbacks that have been committed.
+ */
+ public int getSessionId() {
+ // TODO: Support rollback of staged installs.
+ return PackageInstaller.SessionInfo.INVALID_ID;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -70,7 +90,7 @@ public final class RollbackInfo implements Parcelable {
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mRollbackId);
- targetPackage.writeToParcel(out, flags);
+ out.writeTypedList(mPackages);
}
public static final Parcelable.Creator<RollbackInfo> CREATOR =
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index c1c0bc1d3e07..f8abcfc8fc76 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -17,7 +17,6 @@
package android.content.rollback;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -50,55 +49,26 @@ public final class RollbackManager {
}
/**
- * Returns the rollback currently available to be executed for the given
- * package.
- * <p>
- * The returned RollbackInfo describes what packages would be rolled back,
- * including package version codes before and after rollback. The rollback
- * can be initiated using {@link #executeRollback(RollbackInfo,IntentSender)}.
- * <p>
- * TODO: What if there is no package installed on device for packageName?
+ * Returns a list of all currently available rollbacks.
*
- * @param packageName name of the package to get the availble RollbackInfo for.
- * @return the rollback available for the package, or null if no rollback
- * is available for the package.
* @throws SecurityException if the caller does not have the
* MANAGE_ROLLBACKS permission.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
- public @Nullable RollbackInfo getAvailableRollback(@NonNull String packageName) {
+ public List<RollbackInfo> getAvailableRollbacks() {
try {
- return mBinder.getAvailableRollback(packageName);
+ return mBinder.getAvailableRollbacks().getList();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Gets the names of packages that are available for rollback.
- * Call {@link #getAvailableRollback(String)} to get more information
- * about the rollback available for a particular package.
- *
- * @return the names of packages that are available for rollback.
- * @throws SecurityException if the caller does not have the
- * MANAGE_ROLLBACKS permission.
- */
- @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
- public @NonNull List<String> getPackagesWithAvailableRollbacks() {
- try {
- return mBinder.getPackagesWithAvailableRollbacks().getList();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
-
- /**
- * Gets the list of all recently executed rollbacks.
+ * Gets the list of all recently committed rollbacks.
* This is for the purposes of preventing re-install of a bad version of a
- * package.
+ * package and monitoring the status of a staged rollback.
* <p>
- * Returns an empty list if there are no recently executed rollbacks.
+ * Returns an empty list if there are no recently committed rollbacks.
* <p>
* To avoid having to keep around complete rollback history forever on a
* device, the returned list of rollbacks is only guaranteed to include
@@ -107,12 +77,12 @@ public final class RollbackManager {
* (without the possibility of rollback) to a higher version code than was
* rolled back from.
*
- * @return the recently executed rollbacks
+ * @return the recently committed rollbacks
* @throws SecurityException if the caller does not have the
* MANAGE_ROLLBACKS permission.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
- public @NonNull List<RollbackInfo> getRecentlyExecutedRollbacks() {
+ public @NonNull List<RollbackInfo> getRecentlyCommittedRollbacks() {
try {
return mBinder.getRecentlyExecutedRollbacks().getList();
} catch (RemoteException e) {
@@ -121,28 +91,26 @@ public final class RollbackManager {
}
/**
- * Execute the given rollback, rolling back all versions of the packages
- * to the last good versions previously installed on the device as
- * specified in the given rollback object. The rollback will fail if any
- * of the installed packages or available rollbacks are inconsistent with
- * the versions specified in the given rollback object, which can happen
- * if a package has been updated or a rollback expired since the rollback
- * object was retrieved from {@link #getAvailableRollback(String)}.
+ * Commit the rollback with given id, rolling back all versions of the
+ * packages to the last good versions previously installed on the device
+ * as specified in the corresponding RollbackInfo object. The
+ * rollback will fail if any of the installed packages or available
+ * rollbacks are inconsistent with the versions specified in the given
+ * rollback object, which can happen if a package has been updated or a
+ * rollback expired since the rollback object was retrieved from
+ * {@link #getAvailableRollbacks()}.
* <p>
* TODO: Specify the returns status codes.
- * TODO: What happens in case reboot is required for the rollback to take
- * effect for staged installs?
*
- * @param rollback to execute
+ * @param rollbackId ID of the rollback to commit
* @param statusReceiver where to deliver the results
* @throws SecurityException if the caller does not have the
* MANAGE_ROLLBACKS permission.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
- public void executeRollback(@NonNull RollbackInfo rollback,
- @NonNull IntentSender statusReceiver) {
+ public void commitRollback(int rollbackId, @NonNull IntentSender statusReceiver) {
try {
- mBinder.executeRollback(rollback, mCallerPackageName, statusReceiver);
+ mBinder.commitRollback(rollbackId, mCallerPackageName, statusReceiver);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index 8bcaa4526fa7..b44458a7d449 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -16,17 +16,20 @@
package android.database;
+import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.os.UserHandle;
import android.util.Log;
+import com.android.internal.util.Preconditions;
+
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
@@ -72,6 +75,7 @@ public abstract class AbstractCursor implements CrossProcessCursor {
@UnsupportedAppUsage
private Uri mNotifyUri;
+ private List<Uri> mNotifyUris;
private final Object mSelfObserverLock = new Object();
private ContentObserver mSelfObserver;
@@ -155,7 +159,11 @@ public abstract class AbstractCursor implements CrossProcessCursor {
@Override
public boolean requery() {
if (mSelfObserver != null && mSelfObserverRegistered == false) {
- mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);
+ final int size = mNotifyUris.size();
+ for (int i = 0; i < size; ++i) {
+ final Uri notifyUri = mNotifyUris.get(i);
+ mContentResolver.registerContentObserver(notifyUri, true, mSelfObserver);
+ }
mSelfObserverRegistered = true;
}
mDataSetObservable.notifyChanged();
@@ -384,8 +392,12 @@ public abstract class AbstractCursor implements CrossProcessCursor {
protected void onChange(boolean selfChange) {
synchronized (mSelfObserverLock) {
mContentObservable.dispatchChange(selfChange, null);
- if (mNotifyUri != null && selfChange) {
- mContentResolver.notifyChange(mNotifyUri, mSelfObserver);
+ if (mNotifyUris != null && selfChange) {
+ final int size = mNotifyUris.size();
+ for (int i = 0; i < size; ++i) {
+ final Uri notifyUri = mNotifyUris.get(i);
+ mContentResolver.notifyChange(notifyUri, mSelfObserver);
+ }
}
}
}
@@ -399,19 +411,33 @@ public abstract class AbstractCursor implements CrossProcessCursor {
*/
@Override
public void setNotificationUri(ContentResolver cr, Uri notifyUri) {
- setNotificationUri(cr, notifyUri, cr.getUserId());
+ setNotificationUris(cr, Arrays.asList(notifyUri));
+ }
+
+ @Override
+ public void setNotificationUris(@NonNull ContentResolver cr, @NonNull List<Uri> notifyUris) {
+ Preconditions.checkNotNull(cr);
+ Preconditions.checkNotNull(notifyUris);
+
+ setNotificationUris(cr, notifyUris, cr.getUserId());
}
/** @hide - set the notification uri but with an observer for a particular user's view */
- public void setNotificationUri(ContentResolver cr, Uri notifyUri, int userHandle) {
+ public void setNotificationUris(ContentResolver cr, List<Uri> notifyUris, int userHandle) {
synchronized (mSelfObserverLock) {
- mNotifyUri = notifyUri;
+ mNotifyUris = notifyUris;
+ mNotifyUri = mNotifyUris.get(0);
mContentResolver = cr;
if (mSelfObserver != null) {
mContentResolver.unregisterContentObserver(mSelfObserver);
}
mSelfObserver = new SelfContentObserver(this);
- mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver, userHandle);
+ final int size = mNotifyUris.size();
+ for (int i = 0; i < size; ++i) {
+ final Uri notifyUri = mNotifyUris.get(i);
+ mContentResolver.registerContentObserver(
+ notifyUri, true, mSelfObserver, userHandle);
+ }
mSelfObserverRegistered = true;
}
}
@@ -424,6 +450,13 @@ public abstract class AbstractCursor implements CrossProcessCursor {
}
@Override
+ public List<Uri> getNotificationUris() {
+ synchronized (mSelfObserverLock) {
+ return mNotifyUris;
+ }
+ }
+
+ @Override
public boolean getWantsAllOnMoveCalls() {
return false;
}
diff --git a/core/java/android/database/Cursor.java b/core/java/android/database/Cursor.java
index 5a4280e997cd..1379138b37c0 100644
--- a/core/java/android/database/Cursor.java
+++ b/core/java/android/database/Cursor.java
@@ -16,11 +16,14 @@
package android.database;
+import android.annotation.NonNull;
import android.content.ContentResolver;
import android.net.Uri;
import android.os.Bundle;
import java.io.Closeable;
+import java.util.Arrays;
+import java.util.List;
/**
* This interface provides random read-write access to the result set returned
@@ -421,7 +424,10 @@ public interface Cursor extends Closeable {
/**
* Register to watch a content URI for changes. This can be the URI of a specific data row (for
* example, "content://my_provider_type/23"), or a a generic URI for a content type.
- *
+ *
+ * <p>Calling this overrides any previous call to
+ * {@link #setNotificationUris(ContentResolver, List)}.
+ *
* @param cr The content resolver from the caller's context. The listener attached to
* this resolver will be notified.
* @param uri The content URI to watch.
@@ -429,6 +435,24 @@ public interface Cursor extends Closeable {
void setNotificationUri(ContentResolver cr, Uri uri);
/**
+ * Similar to {@link #setNotificationUri(ContentResolver, Uri)}, except this version allows
+ * to watch multiple content URIs for changes.
+ *
+ * <p>If this is not implemented, this is equivalent to calling
+ * {@link #setNotificationUri(ContentResolver, Uri)} with the first URI in {@code uris}.
+ *
+ * <p>Calling this overrides any previous call to
+ * {@link #setNotificationUri(ContentResolver, Uri)}.
+ *
+ * @param cr The content resolver from the caller's context. The listener attached to
+ * this resolver will be notified.
+ * @param uris The content URIs to watch.
+ */
+ default void setNotificationUris(@NonNull ContentResolver cr, @NonNull List<Uri> uris) {
+ setNotificationUri(cr, uris.get(0));
+ }
+
+ /**
* Return the URI at which notifications of changes in this Cursor's data
* will be delivered, as previously set by {@link #setNotificationUri}.
* @return Returns a URI that can be used with
@@ -439,6 +463,22 @@ public interface Cursor extends Closeable {
Uri getNotificationUri();
/**
+ * Return the URIs at which notifications of changes in this Cursor's data
+ * will be delivered, as previously set by {@link #setNotificationUris}.
+ *
+ * <p>If this is not implemented, this is equivalent to calling {@link #getNotificationUri()}.
+ *
+ * @return Returns URIs that can be used with
+ * {@link ContentResolver#registerContentObserver(android.net.Uri, boolean, ContentObserver)
+ * ContentResolver.registerContentObserver} to find out about changes to this Cursor's
+ * data. May be null if no notification URI has been set.
+ */
+ default List<Uri> getNotificationUris() {
+ final Uri notifyUri = getNotificationUri();
+ return notifyUri == null ? null : Arrays.asList(notifyUri);
+ }
+
+ /**
* onMove() will only be called across processes if this method returns true.
* @return whether all cursor movement should result in a call to onMove().
*/
diff --git a/core/java/android/database/CursorWrapper.java b/core/java/android/database/CursorWrapper.java
index 0d27dfb872f0..c9cafafe4041 100644
--- a/core/java/android/database/CursorWrapper.java
+++ b/core/java/android/database/CursorWrapper.java
@@ -21,6 +21,8 @@ import android.content.ContentResolver;
import android.net.Uri;
import android.os.Bundle;
+import java.util.List;
+
/**
* Wrapper class for Cursor that delegates all calls to the actual cursor object. The primary
* use for this class is to extend a cursor while overriding only a subset of its methods.
@@ -241,11 +243,21 @@ public class CursorWrapper implements Cursor {
}
@Override
+ public void setNotificationUris(ContentResolver cr, List<Uri> uris) {
+ mCursor.setNotificationUris(cr, uris);
+ }
+
+ @Override
public Uri getNotificationUri() {
return mCursor.getNotificationUri();
}
@Override
+ public List<Uri> getNotificationUris() {
+ return mCursor.getNotificationUris();
+ }
+
+ @Override
public void unregisterContentObserver(ContentObserver observer) {
mCursor.unregisterContentObserver(observer);
}
diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
index 9d37d9939127..209afb88ccd3 100644
--- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
@@ -252,12 +252,55 @@ public interface BiometricFaceConstants {
public static final int FACE_ACQUIRED_TOO_SIMILAR = 15;
/**
+ * The magnitude of the pan angle of the user’s face with respect to the sensor’s
+ * capture plane is too high.
+ *
+ * The pan angle is defined as the angle swept out by the user’s face turning
+ * their neck left and right. The pan angle would be zero if the user faced the
+ * camera directly.
+ *
+ * The user should be informed to look more directly at the camera.
+ */
+ public static final int FACE_ACQUIRED_PAN_TOO_EXTREME = 16;
+
+ /**
+ * The magnitude of the tilt angle of the user’s face with respect to the sensor’s
+ * capture plane is too high.
+ *
+ * The tilt angle is defined as the angle swept out by the user’s face looking up
+ * and down. The pan angle would be zero if the user faced the camera directly.
+ *
+ * The user should be informed to look more directly at the camera.
+ */
+ public static final int FACE_ACQUIRED_TILT_TOO_EXTREME = 17;
+
+ /**
+ * The magnitude of the roll angle of the user’s face with respect to the sensor’s
+ * capture plane is too high.
+ *
+ * The roll angle is defined as the angle swept out by the user’s face tilting their head
+ * towards their shoulders to the left and right. The pan angle would be zero if the user
+ * faced the camera directly.
+ *
+ * The user should be informed to look more directly at the camera.
+ */
+ public static final int FACE_ACQUIRED_ROLL_TOO_EXTREME = 18;
+
+ /**
+ * The user’s face has been obscured by some object.
+ *
+ * The user should be informed to remove any objects from the line of sight from
+ * the sensor to the user’s face.
+ */
+ public static final int FACE_ACQUIRED_FACE_OBSCURED = 19;
+
+ /**
* Hardware vendors may extend this list if there are conditions that do not fall under one of
* the above categories. Vendors are responsible for providing error strings for these errors.
*
* @hide
*/
- public static final int FACE_ACQUIRED_VENDOR = 16;
+ public static final int FACE_ACQUIRED_VENDOR = 20;
/**
* @hide
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 8aac1bfa1f8d..5afe1a9309f4 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -171,5 +171,39 @@ public class BiometricManager {
Slog.w(TAG, "resetTimeout(): Service not connected");
}
}
+
+ /**
+ * TODO(b/123378871): Remove when moved.
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void onConfirmDeviceCredentialSuccess() {
+ if (mService != null) {
+ try {
+ mService.onConfirmDeviceCredentialSuccess();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Slog.w(TAG, "onConfirmDeviceCredentialSuccess(): Service not connected");
+ }
+ }
+
+ /**
+ * TODO(b/123378871): Remove when moved.
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void onConfirmDeviceCredentialError(int error, String message) {
+ if (mService != null) {
+ try {
+ mService.onConfirmDeviceCredentialError(error, message);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ Slog.w(TAG, "onConfirmDeviceCredentialError(): Service not connected");
+ }
+ }
}
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index c69b68e4360a..ec62abaab6a2 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -77,6 +77,10 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
* @hide
*/
public static final String KEY_REQUIRE_CONFIRMATION = "require_confirmation";
+ /**
+ * @hide
+ */
+ public static final String KEY_ENABLE_FALLBACK = "enable_fallback";
/**
* Error/help message will show for this amount of time.
@@ -242,6 +246,18 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
}
/**
+ * The user will first be prompted to authenticate with biometrics, but also given the
+ * option to authenticate with their device PIN, pattern, or password.
+ * @param enable When true, the prompt will fall back to ask for the user's device
+ * credentials (PIN, pattern, or password).
+ * @return
+ */
+ public Builder setEnableFallback(boolean enable) {
+ mBundle.putBoolean(KEY_ENABLE_FALLBACK, enable);
+ return this;
+ }
+
+ /**
* Creates a {@link BiometricPrompt}.
* @return a {@link BiometricPrompt}
* @throws IllegalArgumentException if any of the required fields are not set.
@@ -250,11 +266,15 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
final CharSequence title = mBundle.getCharSequence(KEY_TITLE);
final CharSequence negative = mBundle.getCharSequence(KEY_NEGATIVE_TEXT);
final boolean useDefaultTitle = mBundle.getBoolean(KEY_USE_DEFAULT_TITLE);
+ final boolean enableFallback = mBundle.getBoolean(KEY_ENABLE_FALLBACK);
if (TextUtils.isEmpty(title) && !useDefaultTitle) {
throw new IllegalArgumentException("Title must be set and non-empty");
- } else if (TextUtils.isEmpty(negative)) {
+ } else if (TextUtils.isEmpty(negative) && !enableFallback) {
throw new IllegalArgumentException("Negative text must be set and non-empty");
+ } else if (!TextUtils.isEmpty(negative) && enableFallback) {
+ throw new IllegalArgumentException("Can't have both negative button behavior"
+ + " and fallback enabled");
}
return new BiometricPrompt(mContext, mBundle, mPositiveButtonInfo, mNegativeButtonInfo);
}
@@ -514,6 +534,9 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
if (callback == null) {
throw new IllegalArgumentException("Must supply a callback");
}
+ if (mBundle.getBoolean(KEY_ENABLE_FALLBACK)) {
+ throw new IllegalArgumentException("Fallback not supported with crypto");
+ }
authenticateInternal(crypto, cancel, executor, callback, mContext.getUserId());
}
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index de828f2d6757..e4336d171ab6 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -51,4 +51,12 @@ interface IBiometricService {
// Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password)
void resetTimeout(in byte [] token);
+
+ // TODO(b/123378871): Remove when moved.
+ // CDCA needs to send results to BiometricService if it was invoked using BiometricPrompt's
+ // setEnableFallback method, since there's no way for us to intercept onActivityResult.
+ // CDCA is launched from BiometricService (startActivityAsUser) instead of *ForResult.
+ void onConfirmDeviceCredentialSuccess();
+ // TODO(b/123378871): Remove when moved.
+ void onConfirmDeviceCredentialError(int error, String message);
}
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 7e45441c804a..f3ebd7f36fd6 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -20,6 +20,7 @@ import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
+import android.graphics.ColorSpace;
import android.graphics.Point;
import android.hardware.display.DisplayManager.DisplayListener;
import android.media.projection.IMediaProjection;
@@ -80,12 +81,20 @@ public final class DisplayManagerGlobal {
new ArrayList<DisplayListenerDelegate>();
private final SparseArray<DisplayInfo> mDisplayInfoCache = new SparseArray<DisplayInfo>();
+ private final ColorSpace mWideColorSpace;
private int[] mDisplayIdCache;
private int mWifiDisplayScanNestCount;
private DisplayManagerGlobal(IDisplayManager dm) {
mDm = dm;
+ try {
+ mWideColorSpace =
+ ColorSpace.get(
+ ColorSpace.Named.values()[mDm.getPreferredWideGamutColorSpaceId()]);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
}
/**
@@ -495,6 +504,17 @@ public final class DisplayManagerGlobal {
}
/**
+ * Gets the preferred wide gamut color space for all displays.
+ * The wide gamut color space is returned from composition pipeline
+ * based on hardware capability.
+ *
+ * @hide
+ */
+ public ColorSpace getPreferredWideGamutColorSpace() {
+ return mWideColorSpace;
+ }
+
+ /**
* Sets the global brightness configuration for a given user.
*
* @hide
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index aae8afbcad49..5ea8bd67ce75 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -116,4 +116,9 @@ interface IDisplayManager {
// Get the minimum brightness curve.
Curve getMinimumBrightnessCurve();
+
+ // Gets the id of the preferred wide gamut color space for all displays.
+ // The wide gamut color space is returned from composition pipeline
+ // based on hardware capability.
+ int getPreferredWideGamutColorSpaceId();
}
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index b5d822672e70..6c291c25dbdf 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -17,24 +17,39 @@
package android.net;
import android.annotation.UnsupportedAppUsage;
-import android.net.NetworkUtils;
import android.os.Parcel;
+import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
/**
* A simple object for retrieving the results of a DHCP request.
* Optimized (attempted) for that jni interface
- * TODO - remove when DhcpInfo is deprecated. Move the remaining api to LinkProperties.
+ * TODO: remove this class and replace with other existing constructs
* @hide
*/
-public class DhcpResults extends StaticIpConfiguration {
+public final class DhcpResults implements Parcelable {
private static final String TAG = "DhcpResults";
@UnsupportedAppUsage
+ public LinkAddress ipAddress;
+
+ @UnsupportedAppUsage
+ public InetAddress gateway;
+
+ @UnsupportedAppUsage
+ public final ArrayList<InetAddress> dnsServers = new ArrayList<>();
+
+ @UnsupportedAppUsage
+ public String domains;
+
+ @UnsupportedAppUsage
public Inet4Address serverAddress;
/** Vendor specific information (from RFC 2132). */
@@ -48,23 +63,36 @@ public class DhcpResults extends StaticIpConfiguration {
@UnsupportedAppUsage
public int mtu;
- @UnsupportedAppUsage
public DhcpResults() {
super();
}
- @UnsupportedAppUsage
+ /**
+ * Create a {@link StaticIpConfiguration} based on the DhcpResults.
+ */
+ public StaticIpConfiguration toStaticIpConfiguration() {
+ final StaticIpConfiguration s = new StaticIpConfiguration();
+ // All these except dnsServers are immutable, so no need to make copies.
+ s.ipAddress = ipAddress;
+ s.gateway = gateway;
+ s.dnsServers.addAll(dnsServers);
+ s.domains = domains;
+ return s;
+ }
+
public DhcpResults(StaticIpConfiguration source) {
- super(source);
+ if (source != null) {
+ ipAddress = source.ipAddress;
+ gateway = source.gateway;
+ dnsServers.addAll(source.dnsServers);
+ domains = source.domains;
+ }
}
/** copy constructor */
- @UnsupportedAppUsage
public DhcpResults(DhcpResults source) {
- super(source);
-
+ this(source == null ? null : source.toStaticIpConfiguration());
if (source != null) {
- // All these are immutable, so no need to make copies.
serverAddress = source.serverAddress;
vendorInfo = source.vendorInfo;
leaseDuration = source.leaseDuration;
@@ -73,6 +101,14 @@ public class DhcpResults extends StaticIpConfiguration {
}
/**
+ * @see StaticIpConfiguration#getRoutes(String)
+ * @hide
+ */
+ public List<RouteInfo> getRoutes(String iface) {
+ return toStaticIpConfiguration().getRoutes(iface);
+ }
+
+ /**
* Test if this DHCP lease includes vendor hint that network link is
* metered, and sensitive to heavy data transfers.
*/
@@ -85,7 +121,11 @@ public class DhcpResults extends StaticIpConfiguration {
}
public void clear() {
- super.clear();
+ ipAddress = null;
+ gateway = null;
+ dnsServers.clear();
+ domains = null;
+ serverAddress = null;
vendorInfo = null;
leaseDuration = 0;
mtu = 0;
@@ -111,20 +151,20 @@ public class DhcpResults extends StaticIpConfiguration {
DhcpResults target = (DhcpResults)obj;
- return super.equals((StaticIpConfiguration) obj) &&
- Objects.equals(serverAddress, target.serverAddress) &&
- Objects.equals(vendorInfo, target.vendorInfo) &&
- leaseDuration == target.leaseDuration &&
- mtu == target.mtu;
+ return toStaticIpConfiguration().equals(target.toStaticIpConfiguration())
+ && Objects.equals(serverAddress, target.serverAddress)
+ && Objects.equals(vendorInfo, target.vendorInfo)
+ && leaseDuration == target.leaseDuration
+ && mtu == target.mtu;
}
- /** Implement the Parcelable interface */
+ /**
+ * Implement the Parcelable interface
+ */
public static final Creator<DhcpResults> CREATOR =
new Creator<DhcpResults>() {
public DhcpResults createFromParcel(Parcel in) {
- DhcpResults dhcpResults = new DhcpResults();
- readFromParcel(dhcpResults, in);
- return dhcpResults;
+ return readFromParcel(in);
}
public DhcpResults[] newArray(int size) {
@@ -134,19 +174,26 @@ public class DhcpResults extends StaticIpConfiguration {
/** Implement the Parcelable interface */
public void writeToParcel(Parcel dest, int flags) {
- super.writeToParcel(dest, flags);
+ toStaticIpConfiguration().writeToParcel(dest, flags);
dest.writeInt(leaseDuration);
dest.writeInt(mtu);
NetworkUtils.parcelInetAddress(dest, serverAddress, flags);
dest.writeString(vendorInfo);
}
- private static void readFromParcel(DhcpResults dhcpResults, Parcel in) {
- StaticIpConfiguration.readFromParcel(dhcpResults, in);
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ private static DhcpResults readFromParcel(Parcel in) {
+ final StaticIpConfiguration s = StaticIpConfiguration.CREATOR.createFromParcel(in);
+ final DhcpResults dhcpResults = new DhcpResults(s);
dhcpResults.leaseDuration = in.readInt();
dhcpResults.mtu = in.readInt();
dhcpResults.serverAddress = (Inet4Address) NetworkUtils.unparcelInetAddress(in);
dhcpResults.vendorInfo = in.readString();
+ return dhcpResults;
}
// Utils for jni population - false on success
@@ -184,25 +231,70 @@ public class DhcpResults extends StaticIpConfiguration {
return false;
}
- public boolean setServerAddress(String addrString) {
- try {
- serverAddress = (Inet4Address) NetworkUtils.numericToInetAddress(addrString);
- } catch (IllegalArgumentException|ClassCastException e) {
- Log.e(TAG, "setServerAddress failed with addrString " + addrString);
- return true;
- }
- return false;
+ public LinkAddress getIpAddress() {
+ return ipAddress;
+ }
+
+ public void setIpAddress(LinkAddress ipAddress) {
+ this.ipAddress = ipAddress;
+ }
+
+ public InetAddress getGateway() {
+ return gateway;
+ }
+
+ public void setGateway(InetAddress gateway) {
+ this.gateway = gateway;
+ }
+
+ public List<InetAddress> getDnsServers() {
+ return dnsServers;
+ }
+
+ /**
+ * Add a DNS server to this configuration.
+ */
+ public void addDnsServer(InetAddress server) {
+ dnsServers.add(server);
+ }
+
+ public String getDomains() {
+ return domains;
+ }
+
+ public void setDomains(String domains) {
+ this.domains = domains;
+ }
+
+ public Inet4Address getServerAddress() {
+ return serverAddress;
+ }
+
+ public void setServerAddress(Inet4Address addr) {
+ serverAddress = addr;
+ }
+
+ public int getLeaseDuration() {
+ return leaseDuration;
}
public void setLeaseDuration(int duration) {
leaseDuration = duration;
}
+ public String getVendorInfo() {
+ return vendorInfo;
+ }
+
public void setVendorInfo(String info) {
vendorInfo = info;
}
- public void setDomains(String newDomains) {
- domains = newDomains;
+ public int getMtu() {
+ return mtu;
+ }
+
+ public void setMtu(int mtu) {
+ this.mtu = mtu;
}
}
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 23c8aa368d87..e519fdf65e50 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -257,7 +257,6 @@ public final class IpSecTransform implements AutoCloseable {
*
* @hide
*/
- @SystemApi
public static class NattKeepaliveCallback {
/** The specified {@code Network} is not connected. */
public static final int ERROR_INVALID_NETWORK = 1;
@@ -288,7 +287,6 @@ public final class IpSecTransform implements AutoCloseable {
*
* @hide
*/
- @SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
@@ -331,7 +329,6 @@ public final class IpSecTransform implements AutoCloseable {
*
* @hide
*/
- @SystemApi
@RequiresPermission(anyOf = {
android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index c996d01fe8e4..39db4fef78b5 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -21,8 +21,10 @@ import static android.system.OsConstants.AF_INET6;
import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
+import android.net.shared.Inet4AddressUtils;
import android.os.Build;
import android.os.Parcel;
+import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;
import android.util.Pair;
@@ -39,8 +41,6 @@ import java.util.Collection;
import java.util.Locale;
import java.util.TreeSet;
-import android.system.ErrnoException;
-
/**
* Native methods for managing network interfaces.
*
@@ -177,119 +177,37 @@ public class NetworkUtils {
FileDescriptor fd) throws IOException;
/**
- * @see #intToInet4AddressHTL(int)
- * @deprecated Use either {@link #intToInet4AddressHTH(int)}
- * or {@link #intToInet4AddressHTL(int)}
+ * @see Inet4AddressUtils#intToInet4AddressHTL(int)
+ * @deprecated Use either {@link Inet4AddressUtils#intToInet4AddressHTH(int)}
+ * or {@link Inet4AddressUtils#intToInet4AddressHTL(int)}
*/
@Deprecated
@UnsupportedAppUsage
public static InetAddress intToInetAddress(int hostAddress) {
- return intToInet4AddressHTL(hostAddress);
- }
-
- /**
- * Convert a IPv4 address from an integer to an InetAddress (0x04030201 -> 1.2.3.4)
- *
- * <p>This method uses the higher-order int bytes as the lower-order IPv4 address bytes,
- * which is an unusual convention. Consider {@link #intToInet4AddressHTH(int)} instead.
- * @param hostAddress an int coding for an IPv4 address, where higher-order int byte is
- * lower-order IPv4 address byte
- */
- public static Inet4Address intToInet4AddressHTL(int hostAddress) {
- return intToInet4AddressHTH(Integer.reverseBytes(hostAddress));
+ return Inet4AddressUtils.intToInet4AddressHTL(hostAddress);
}
/**
- * Convert a IPv4 address from an integer to an InetAddress (0x01020304 -> 1.2.3.4)
- * @param hostAddress an int coding for an IPv4 address
- */
- public static Inet4Address intToInet4AddressHTH(int hostAddress) {
- byte[] addressBytes = { (byte) (0xff & (hostAddress >> 24)),
- (byte) (0xff & (hostAddress >> 16)),
- (byte) (0xff & (hostAddress >> 8)),
- (byte) (0xff & hostAddress) };
-
- try {
- return (Inet4Address) InetAddress.getByAddress(addressBytes);
- } catch (UnknownHostException e) {
- throw new AssertionError();
- }
- }
-
- /**
- * @see #inet4AddressToIntHTL(Inet4Address)
- * @deprecated Use either {@link #inet4AddressToIntHTH(Inet4Address)}
- * or {@link #inet4AddressToIntHTL(Inet4Address)}
+ * @see Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)
+ * @deprecated Use either {@link Inet4AddressUtils#inet4AddressToIntHTH(Inet4Address)}
+ * or {@link Inet4AddressUtils#inet4AddressToIntHTL(Inet4Address)}
*/
@Deprecated
public static int inetAddressToInt(Inet4Address inetAddr)
throws IllegalArgumentException {
- return inet4AddressToIntHTL(inetAddr);
- }
-
- /**
- * Convert an IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x01020304)
- *
- * <p>This conversion can help order IP addresses: considering the ordering
- * 192.0.2.1 < 192.0.2.2 < ..., resulting ints will follow that ordering if read as unsigned
- * integers with {@link Integer#toUnsignedLong}.
- * @param inetAddr is an InetAddress corresponding to the IPv4 address
- * @return the IP address as integer
- */
- public static int inet4AddressToIntHTH(Inet4Address inetAddr)
- throws IllegalArgumentException {
- byte [] addr = inetAddr.getAddress();
- return ((addr[0] & 0xff) << 24) | ((addr[1] & 0xff) << 16)
- | ((addr[2] & 0xff) << 8) | (addr[3] & 0xff);
- }
-
- /**
- * Convert a IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x04030201)
- *
- * <p>This method stores the higher-order IPv4 address bytes in the lower-order int bytes,
- * which is an unusual convention. Consider {@link #inet4AddressToIntHTH(Inet4Address)} instead.
- * @param inetAddr is an InetAddress corresponding to the IPv4 address
- * @return the IP address as integer
- */
- public static int inet4AddressToIntHTL(Inet4Address inetAddr) {
- return Integer.reverseBytes(inet4AddressToIntHTH(inetAddr));
+ return Inet4AddressUtils.inet4AddressToIntHTL(inetAddr);
}
/**
- * @see #prefixLengthToV4NetmaskIntHTL(int)
- * @deprecated Use either {@link #prefixLengthToV4NetmaskIntHTH(int)}
- * or {@link #prefixLengthToV4NetmaskIntHTL(int)}
+ * @see Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)
+ * @deprecated Use either {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTH(int)}
+ * or {@link Inet4AddressUtils#prefixLengthToV4NetmaskIntHTL(int)}
*/
@Deprecated
@UnsupportedAppUsage
public static int prefixLengthToNetmaskInt(int prefixLength)
throws IllegalArgumentException {
- return prefixLengthToV4NetmaskIntHTL(prefixLength);
- }
-
- /**
- * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0xffff8000)
- * @return the IPv4 netmask as an integer
- */
- public static int prefixLengthToV4NetmaskIntHTH(int prefixLength)
- throws IllegalArgumentException {
- if (prefixLength < 0 || prefixLength > 32) {
- throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)");
- }
- // (int)a << b is equivalent to a << (b & 0x1f): can't shift by 32 (-1 << 32 == -1)
- return prefixLength == 0 ? 0 : 0xffffffff << (32 - prefixLength);
- }
-
- /**
- * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0x0080ffff).
- *
- * <p>This method stores the higher-order IPv4 address bytes in the lower-order int bytes,
- * which is an unusual convention. Consider {@link #prefixLengthToV4NetmaskIntHTH(int)} instead.
- * @return the IPv4 netmask as an integer
- */
- public static int prefixLengthToV4NetmaskIntHTL(int prefixLength)
- throws IllegalArgumentException {
- return Integer.reverseBytes(prefixLengthToV4NetmaskIntHTH(prefixLength));
+ return Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL(prefixLength);
}
/**
@@ -307,17 +225,13 @@ public class NetworkUtils {
* @return the network prefix length
* @throws IllegalArgumentException the specified netmask was not contiguous.
* @hide
+ * @deprecated use {@link Inet4AddressUtils#netmaskToPrefixLength(Inet4Address)}
*/
@UnsupportedAppUsage
+ @Deprecated
public static int netmaskToPrefixLength(Inet4Address netmask) {
- // inetAddressToInt returns an int in *network* byte order.
- int i = Integer.reverseBytes(inetAddressToInt(netmask));
- int prefixLength = Integer.bitCount(i);
- int trailingZeros = Integer.numberOfTrailingZeros(i);
- if (trailingZeros != 32 - prefixLength) {
- throw new IllegalArgumentException("Non-contiguous netmask: " + Integer.toHexString(i));
- }
- return prefixLength;
+ // This is only here because some apps seem to be using it (@UnsupportedAppUsage).
+ return Inet4AddressUtils.netmaskToPrefixLength(netmask);
}
@@ -408,16 +322,8 @@ public class NetworkUtils {
*/
@UnsupportedAppUsage
public static int getImplicitNetmask(Inet4Address address) {
- int firstByte = address.getAddress()[0] & 0xff; // Convert to an unsigned value.
- if (firstByte < 128) {
- return 8;
- } else if (firstByte < 192) {
- return 16;
- } else if (firstByte < 224) {
- return 24;
- } else {
- return 32; // Will likely not end well for other reasons.
- }
+ // Only here because it seems to be used by apps
+ return Inet4AddressUtils.getImplicitNetmask(address);
}
/**
@@ -445,28 +351,6 @@ public class NetworkUtils {
}
/**
- * Get a prefix mask as Inet4Address for a given prefix length.
- *
- * <p>For example 20 -> 255.255.240.0
- */
- public static Inet4Address getPrefixMaskAsInet4Address(int prefixLength)
- throws IllegalArgumentException {
- return intToInet4AddressHTH(prefixLengthToV4NetmaskIntHTH(prefixLength));
- }
-
- /**
- * Get the broadcast address for a given prefix.
- *
- * <p>For example 192.168.0.1/24 -> 192.168.0.255
- */
- public static Inet4Address getBroadcastAddress(Inet4Address addr, int prefixLength)
- throws IllegalArgumentException {
- final int intBroadcastAddr = inet4AddressToIntHTH(addr)
- | ~prefixLengthToV4NetmaskIntHTH(prefixLength);
- return intToInet4AddressHTH(intBroadcastAddr);
- }
-
- /**
* Check if IP address type is consistent between two InetAddress.
* @return true if both are the same type. False otherwise.
*/
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index 3aa56b90251f..25bae3c57423 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -16,10 +16,11 @@
package android.net;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
-import android.net.LinkAddress;
-import android.os.Parcelable;
import android.os.Parcel;
+import android.os.Parcelable;
import java.net.InetAddress;
import java.util.ArrayList;
@@ -46,17 +47,22 @@ import java.util.Objects;
*
* @hide
*/
-public class StaticIpConfiguration implements Parcelable {
+@SystemApi
+@TestApi
+public final class StaticIpConfiguration implements Parcelable {
+ /** @hide */
@UnsupportedAppUsage
public LinkAddress ipAddress;
+ /** @hide */
@UnsupportedAppUsage
public InetAddress gateway;
+ /** @hide */
@UnsupportedAppUsage
public final ArrayList<InetAddress> dnsServers;
+ /** @hide */
@UnsupportedAppUsage
public String domains;
- @UnsupportedAppUsage
public StaticIpConfiguration() {
dnsServers = new ArrayList<InetAddress>();
}
@@ -79,6 +85,41 @@ public class StaticIpConfiguration implements Parcelable {
domains = null;
}
+ public LinkAddress getIpAddress() {
+ return ipAddress;
+ }
+
+ public void setIpAddress(LinkAddress ipAddress) {
+ this.ipAddress = ipAddress;
+ }
+
+ public InetAddress getGateway() {
+ return gateway;
+ }
+
+ public void setGateway(InetAddress gateway) {
+ this.gateway = gateway;
+ }
+
+ public List<InetAddress> getDnsServers() {
+ return dnsServers;
+ }
+
+ public String getDomains() {
+ return domains;
+ }
+
+ public void setDomains(String newDomains) {
+ domains = newDomains;
+ }
+
+ /**
+ * Add a DNS server to this configuration.
+ */
+ public void addDnsServer(InetAddress server) {
+ dnsServers.add(server);
+ }
+
/**
* Returns the network routes specified by this object. Will typically include a
* directly-connected route for the IP address's local subnet and a default route. If the
@@ -86,7 +127,6 @@ public class StaticIpConfiguration implements Parcelable {
* route to the gateway as well. This configuration is arguably invalid, but it used to work
* in K and earlier, and other OSes appear to accept it.
*/
- @UnsupportedAppUsage
public List<RouteInfo> getRoutes(String iface) {
List<RouteInfo> routes = new ArrayList<RouteInfo>(3);
if (ipAddress != null) {
@@ -107,6 +147,7 @@ public class StaticIpConfiguration implements Parcelable {
* contained in the LinkProperties will not be a complete picture of the link's configuration,
* because any configuration information that is obtained dynamically by the network (e.g.,
* IPv6 configuration) will not be included.
+ * @hide
*/
public LinkProperties toLinkProperties(String iface) {
LinkProperties lp = new LinkProperties();
@@ -124,6 +165,7 @@ public class StaticIpConfiguration implements Parcelable {
return lp;
}
+ @Override
public String toString() {
StringBuffer str = new StringBuffer();
@@ -143,6 +185,7 @@ public class StaticIpConfiguration implements Parcelable {
return str.toString();
}
+ @Override
public int hashCode() {
int result = 13;
result = 47 * result + (ipAddress == null ? 0 : ipAddress.hashCode());
@@ -168,12 +211,10 @@ public class StaticIpConfiguration implements Parcelable {
}
/** Implement the Parcelable interface */
- public static Creator<StaticIpConfiguration> CREATOR =
+ public static final Creator<StaticIpConfiguration> CREATOR =
new Creator<StaticIpConfiguration>() {
public StaticIpConfiguration createFromParcel(Parcel in) {
- StaticIpConfiguration s = new StaticIpConfiguration();
- readFromParcel(s, in);
- return s;
+ return readFromParcel(in);
}
public StaticIpConfiguration[] newArray(int size) {
@@ -182,11 +223,13 @@ public class StaticIpConfiguration implements Parcelable {
};
/** Implement the Parcelable interface */
+ @Override
public int describeContents() {
return 0;
}
/** Implement the Parcelable interface */
+ @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(ipAddress, flags);
NetworkUtils.parcelInetAddress(dest, gateway, flags);
@@ -197,7 +240,9 @@ public class StaticIpConfiguration implements Parcelable {
dest.writeString(domains);
}
- protected static void readFromParcel(StaticIpConfiguration s, Parcel in) {
+ /** @hide */
+ public static StaticIpConfiguration readFromParcel(Parcel in) {
+ final StaticIpConfiguration s = new StaticIpConfiguration();
s.ipAddress = in.readParcelable(null);
s.gateway = NetworkUtils.unparcelInetAddress(in);
s.dnsServers.clear();
@@ -206,5 +251,6 @@ public class StaticIpConfiguration implements Parcelable {
s.dnsServers.add(NetworkUtils.unparcelInetAddress(in));
}
s.domains = in.readString();
+ return s;
}
}
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java
index f28cdc902848..73cf94b785a7 100644
--- a/core/java/android/net/apf/ApfCapabilities.java
+++ b/core/java/android/net/apf/ApfCapabilities.java
@@ -16,11 +16,16 @@
package android.net.apf;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
+
/**
* APF program support capabilities.
*
* @hide
*/
+@SystemApi
+@TestApi
public class ApfCapabilities {
/**
* Version of APF instruction set supported for packet filtering. 0 indicates no support for
diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
index 1634694cc71f..7432687e136f 100644
--- a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
+++ b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
@@ -17,11 +17,15 @@
package android.net.captiveportal;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
/**
* Result of calling isCaptivePortal().
* @hide
*/
+@SystemApi
+@TestApi
public final class CaptivePortalProbeResult {
public static final int SUCCESS_CODE = 204;
public static final int FAILED_CODE = 599;
diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java b/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
index 57a926afec54..7ad4ecf2264c 100644
--- a/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
+++ b/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
@@ -21,21 +21,26 @@ import static android.net.captiveportal.CaptivePortalProbeResult.SUCCESS_CODE;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/** @hide */
+@SystemApi
+@TestApi
public abstract class CaptivePortalProbeSpec {
- public static final String HTTP_LOCATION_HEADER_NAME = "Location";
-
private static final String TAG = CaptivePortalProbeSpec.class.getSimpleName();
private static final String REGEX_SEPARATOR = "@@/@@";
private static final String SPEC_SEPARATOR = "@@,@@";
@@ -55,7 +60,9 @@ public abstract class CaptivePortalProbeSpec {
* @throws MalformedURLException The URL has invalid format for {@link URL#URL(String)}.
* @throws ParseException The string is empty, does not match the above format, or a regular
* expression is invalid for {@link Pattern#compile(String)}.
+ * @hide
*/
+ @VisibleForTesting
@NonNull
public static CaptivePortalProbeSpec parseSpec(String spec) throws ParseException,
MalformedURLException {
@@ -113,7 +120,8 @@ public abstract class CaptivePortalProbeSpec {
* <p>Each spec is separated by @@,@@ and follows the format for {@link #parseSpec(String)}.
* <p>This method does not throw but ignores any entry that could not be parsed.
*/
- public static CaptivePortalProbeSpec[] parseCaptivePortalProbeSpecs(String settingsVal) {
+ public static Collection<CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(
+ String settingsVal) {
List<CaptivePortalProbeSpec> specs = new ArrayList<>();
if (settingsVal != null) {
for (String spec : TextUtils.split(settingsVal, SPEC_SEPARATOR)) {
@@ -128,7 +136,7 @@ public abstract class CaptivePortalProbeSpec {
if (specs.isEmpty()) {
Log.e(TAG, String.format("could not create any validation spec from %s", settingsVal));
}
- return specs.toArray(new CaptivePortalProbeSpec[specs.size()]);
+ return specs;
}
/**
diff --git a/core/java/android/net/shared/Inet4AddressUtils.java b/core/java/android/net/shared/Inet4AddressUtils.java
new file mode 100644
index 000000000000..bec0c84fa689
--- /dev/null
+++ b/core/java/android/net/shared/Inet4AddressUtils.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * Collection of utilities to work with IPv4 addresses.
+ * @hide
+ */
+public class Inet4AddressUtils {
+
+ /**
+ * Convert a IPv4 address from an integer to an InetAddress (0x04030201 -> 1.2.3.4)
+ *
+ * <p>This method uses the higher-order int bytes as the lower-order IPv4 address bytes,
+ * which is an unusual convention. Consider {@link #intToInet4AddressHTH(int)} instead.
+ * @param hostAddress an int coding for an IPv4 address, where higher-order int byte is
+ * lower-order IPv4 address byte
+ */
+ public static Inet4Address intToInet4AddressHTL(int hostAddress) {
+ return intToInet4AddressHTH(Integer.reverseBytes(hostAddress));
+ }
+
+ /**
+ * Convert a IPv4 address from an integer to an InetAddress (0x01020304 -> 1.2.3.4)
+ * @param hostAddress an int coding for an IPv4 address
+ */
+ public static Inet4Address intToInet4AddressHTH(int hostAddress) {
+ byte[] addressBytes = { (byte) (0xff & (hostAddress >> 24)),
+ (byte) (0xff & (hostAddress >> 16)),
+ (byte) (0xff & (hostAddress >> 8)),
+ (byte) (0xff & hostAddress) };
+
+ try {
+ return (Inet4Address) InetAddress.getByAddress(addressBytes);
+ } catch (UnknownHostException e) {
+ throw new AssertionError();
+ }
+ }
+
+ /**
+ * Convert an IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x01020304)
+ *
+ * <p>This conversion can help order IP addresses: considering the ordering
+ * 192.0.2.1 < 192.0.2.2 < ..., resulting ints will follow that ordering if read as unsigned
+ * integers with {@link Integer#toUnsignedLong}.
+ * @param inetAddr is an InetAddress corresponding to the IPv4 address
+ * @return the IP address as integer
+ */
+ public static int inet4AddressToIntHTH(Inet4Address inetAddr)
+ throws IllegalArgumentException {
+ byte [] addr = inetAddr.getAddress();
+ return ((addr[0] & 0xff) << 24) | ((addr[1] & 0xff) << 16)
+ | ((addr[2] & 0xff) << 8) | (addr[3] & 0xff);
+ }
+
+ /**
+ * Convert a IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x04030201)
+ *
+ * <p>This method stores the higher-order IPv4 address bytes in the lower-order int bytes,
+ * which is an unusual convention. Consider {@link #inet4AddressToIntHTH(Inet4Address)} instead.
+ * @param inetAddr is an InetAddress corresponding to the IPv4 address
+ * @return the IP address as integer
+ */
+ public static int inet4AddressToIntHTL(Inet4Address inetAddr) {
+ return Integer.reverseBytes(inet4AddressToIntHTH(inetAddr));
+ }
+
+ /**
+ * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0xffff8000)
+ * @return the IPv4 netmask as an integer
+ */
+ public static int prefixLengthToV4NetmaskIntHTH(int prefixLength)
+ throws IllegalArgumentException {
+ if (prefixLength < 0 || prefixLength > 32) {
+ throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)");
+ }
+ // (int)a << b is equivalent to a << (b & 0x1f): can't shift by 32 (-1 << 32 == -1)
+ return prefixLength == 0 ? 0 : 0xffffffff << (32 - prefixLength);
+ }
+
+ /**
+ * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0x0080ffff).
+ *
+ * <p>This method stores the higher-order IPv4 address bytes in the lower-order int bytes,
+ * which is an unusual convention. Consider {@link #prefixLengthToV4NetmaskIntHTH(int)} instead.
+ * @return the IPv4 netmask as an integer
+ */
+ public static int prefixLengthToV4NetmaskIntHTL(int prefixLength)
+ throws IllegalArgumentException {
+ return Integer.reverseBytes(prefixLengthToV4NetmaskIntHTH(prefixLength));
+ }
+
+ /**
+ * Convert an IPv4 netmask to a prefix length, checking that the netmask is contiguous.
+ * @param netmask as a {@code Inet4Address}.
+ * @return the network prefix length
+ * @throws IllegalArgumentException the specified netmask was not contiguous.
+ * @hide
+ */
+ public static int netmaskToPrefixLength(Inet4Address netmask) {
+ // inetAddressToInt returns an int in *network* byte order.
+ int i = inet4AddressToIntHTH(netmask);
+ int prefixLength = Integer.bitCount(i);
+ int trailingZeros = Integer.numberOfTrailingZeros(i);
+ if (trailingZeros != 32 - prefixLength) {
+ throw new IllegalArgumentException("Non-contiguous netmask: " + Integer.toHexString(i));
+ }
+ return prefixLength;
+ }
+
+ /**
+ * Returns the implicit netmask of an IPv4 address, as was the custom before 1993.
+ */
+ public static int getImplicitNetmask(Inet4Address address) {
+ int firstByte = address.getAddress()[0] & 0xff; // Convert to an unsigned value.
+ if (firstByte < 128) {
+ return 8;
+ } else if (firstByte < 192) {
+ return 16;
+ } else if (firstByte < 224) {
+ return 24;
+ } else {
+ return 32; // Will likely not end well for other reasons.
+ }
+ }
+
+ /**
+ * Get the broadcast address for a given prefix.
+ *
+ * <p>For example 192.168.0.1/24 -> 192.168.0.255
+ */
+ public static Inet4Address getBroadcastAddress(Inet4Address addr, int prefixLength)
+ throws IllegalArgumentException {
+ final int intBroadcastAddr = inet4AddressToIntHTH(addr)
+ | ~prefixLengthToV4NetmaskIntHTH(prefixLength);
+ return intToInet4AddressHTH(intBroadcastAddr);
+ }
+
+ /**
+ * Get a prefix mask as Inet4Address for a given prefix length.
+ *
+ * <p>For example 20 -> 255.255.240.0
+ */
+ public static Inet4Address getPrefixMaskAsInet4Address(int prefixLength)
+ throws IllegalArgumentException {
+ return intToInet4AddressHTH(prefixLengthToV4NetmaskIntHTH(prefixLength));
+ }
+}
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 6f5f8072f471..3a5b8a86204e 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -21,6 +21,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
import android.os.IBinder.DeathRecipient;
@@ -35,8 +36,7 @@ import java.util.concurrent.Executor;
*
* @hide
*/
-// TODO: Expose API when the implementation is more complete.
-//@SystemApi
+@SystemApi
@SystemService(Context.BUGREPORT_SERVICE)
public class BugreportManager {
private final Context mContext;
diff --git a/core/java/android/os/BugreportParams.java b/core/java/android/os/BugreportParams.java
index 4e696aed1fa8..3871375cfced 100644
--- a/core/java/android/os/BugreportParams.java
+++ b/core/java/android/os/BugreportParams.java
@@ -17,6 +17,7 @@
package android.os;
import android.annotation.IntDef;
+import android.annotation.SystemApi;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -26,8 +27,7 @@ import java.lang.annotation.RetentionPolicy;
*
* @hide
*/
-// TODO: Expose API when the implementation is more complete.
-// @SystemApi
+@SystemApi
public final class BugreportParams {
private final int mMode;
diff --git a/core/java/android/os/ExternalVibration.aidl b/core/java/android/os/ExternalVibration.aidl
new file mode 100644
index 000000000000..2629a401541d
--- /dev/null
+++ b/core/java/android/os/ExternalVibration.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+parcelable ExternalVibration cpp_header "vibrator/ExternalVibration.h";
diff --git a/core/java/android/os/ExternalVibration.java b/core/java/android/os/ExternalVibration.java
new file mode 100644
index 000000000000..69ab1d94a9e2
--- /dev/null
+++ b/core/java/android/os/ExternalVibration.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.annotation.NonNull;
+import android.media.AudioAttributes;
+import android.util.Slog;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * An ExternalVibration represents an on-going vibration being controlled by something other than
+ * the core vibrator service.
+ *
+ * @hide
+ */
+public class ExternalVibration implements Parcelable {
+ private static final String TAG = "ExternalVibration";
+ private int mUid;
+ @NonNull
+ private String mPkg;
+ @NonNull
+ private AudioAttributes mAttrs;
+ @NonNull
+ private IExternalVibrationController mController;
+ // A token used to maintain equality comparisons when passing objects across process
+ // boundaries.
+ @NonNull
+ private IBinder mToken;
+
+ public ExternalVibration(int uid, @NonNull String pkg, @NonNull AudioAttributes attrs,
+ @NonNull IExternalVibrationController controller) {
+ mUid = uid;
+ mPkg = Preconditions.checkNotNull(pkg);
+ mAttrs = Preconditions.checkNotNull(attrs);
+ mController = Preconditions.checkNotNull(controller);
+ mToken = new Binder();
+ }
+
+ private ExternalVibration(Parcel in) {
+ mUid = in.readInt();
+ mPkg = in.readString();
+ mAttrs = readAudioAttributes(in);
+ mController = IExternalVibrationController.Stub.asInterface(in.readStrongBinder());
+ mToken = in.readStrongBinder();
+ }
+
+ private AudioAttributes readAudioAttributes(Parcel in) {
+ int usage = in.readInt();
+ int contentType = in.readInt();
+ int capturePreset = in.readInt();
+ int flags = in.readInt();
+ AudioAttributes.Builder builder = new AudioAttributes.Builder();
+ return builder.setUsage(usage)
+ .setContentType(contentType)
+ .setCapturePreset(capturePreset)
+ .setFlags(flags)
+ .build();
+ }
+
+ public int getUid() {
+ return mUid;
+ }
+
+ public String getPackage() {
+ return mPkg;
+ }
+
+ public AudioAttributes getAudioAttributes() {
+ return mAttrs;
+ }
+
+ /**
+ * Mutes the external vibration if it's playing and unmuted.
+ *
+ * @return whether the muting operation was successful
+ */
+ public boolean mute() {
+ try {
+ mController.mute();
+ } catch (RemoteException e) {
+ Slog.wtf(TAG, "Failed to mute vibration stream: " + this, e);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Unmutes the external vibration if it's playing and muted.
+ *
+ * @return whether the unmuting operation was successful
+ */
+ public boolean unmute() {
+ try {
+ mController.unmute();
+ } catch (RemoteException e) {
+ Slog.wtf(TAG, "Failed to unmute vibration stream: " + this, e);
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || !(o instanceof ExternalVibration)) {
+ return false;
+ }
+ ExternalVibration other = (ExternalVibration) o;
+ return mToken.equals(other.mToken);
+ }
+
+ @Override
+ public String toString() {
+ return "ExternalVibration{"
+ + "uid=" + mUid + ", "
+ + "pkg=" + mPkg + ", "
+ + "attrs=" + mAttrs + ", "
+ + "controller=" + mController
+ + "token=" + mController
+ + "}";
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(mUid);
+ out.writeString(mPkg);
+ writeAudioAttributes(mAttrs, out, flags);
+ out.writeParcelable(mAttrs, flags);
+ out.writeStrongBinder(mController.asBinder());
+ out.writeStrongBinder(mToken);
+ }
+
+ private static void writeAudioAttributes(AudioAttributes attrs, Parcel out, int flags) {
+ out.writeInt(attrs.getUsage());
+ out.writeInt(attrs.getContentType());
+ out.writeInt(attrs.getCapturePreset());
+ out.writeInt(attrs.getAllFlags());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<ExternalVibration> CREATOR =
+ new Parcelable.Creator<ExternalVibration>() {
+ @Override
+ public ExternalVibration createFromParcel(Parcel in) {
+ return new ExternalVibration(in);
+ }
+
+ @Override
+ public ExternalVibration[] newArray(int size) {
+ return new ExternalVibration[size];
+ }
+ };
+}
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 51c3c4c25ce0..629289bb7a45 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -39,6 +39,7 @@ import static android.system.OsConstants.W_OK;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.content.ContentResolver;
import android.provider.DocumentsContract.Document;
import android.system.ErrnoException;
@@ -852,6 +853,7 @@ public class FileUtils {
*
* @hide
*/
+ @TestApi
public static boolean contains(File dir, File file) {
if (dir == null || file == null) return false;
return contains(dir.getAbsolutePath(), file.getAbsolutePath());
diff --git a/core/java/android/os/IExternalVibrationController.aidl b/core/java/android/os/IExternalVibrationController.aidl
new file mode 100644
index 000000000000..56da8c7cd46c
--- /dev/null
+++ b/core/java/android/os/IExternalVibrationController.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * {@hide}
+ */
+
+interface IExternalVibrationController {
+ /**
+ * A method to ask a currently playing vibration to mute (i.e. not vibrate).
+ *
+ * This method is only valid from the time that
+ * {@link IExternalVibratorService#onExternalVibrationStart} returns until
+ * {@link IExternalVibratorService#onExternalVibrationStop} returns.
+ *
+ * @return whether the mute operation was successful
+ */
+ boolean mute();
+
+ /**
+ * A method to ask a currently playing vibration to unmute (i.e. start vibrating).
+ *
+ * This method is only valid from the time that
+ * {@link IExternalVibratorService#onExternalVibrationStart} returns until
+ * {@link IExternalVibratorService#onExternalVibrationStop} returns.
+ *
+ * @return whether the unmute operation was successful
+ */
+ boolean unmute();
+}
diff --git a/core/java/android/os/IExternalVibratorService.aidl b/core/java/android/os/IExternalVibratorService.aidl
new file mode 100644
index 000000000000..666171fcbcb3
--- /dev/null
+++ b/core/java/android/os/IExternalVibratorService.aidl
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.os.ExternalVibration;
+
+/**
+ * The communication channel by which an external system that wants to control the system
+ * vibrator can notify the vibrator subsystem.
+ *
+ * Some vibrators can be driven via multiple paths (e.g. as an audio channel) in addition to
+ * the usual interface, but we typically only want one vibration at a time playing because they
+ * don't mix well. In order to synchronize the two places where vibration might be controlled,
+ * we provide this interface so the vibrator subsystem has a chance to:
+ *
+ * 1) Decide whether the current vibration should play based on the current system policy.
+ * 2) Stop any currently on-going vibrations.
+ * {@hide}
+ */
+interface IExternalVibratorService {
+ const int SCALE_MUTE = -100;
+ const int SCALE_VERY_LOW = -2;
+ const int SCALE_LOW = -1;
+ const int SCALE_NONE = 0;
+ const int SCALE_HIGH = 1;
+ const int SCALE_VERY_HIGH = 2;
+
+ /**
+ * A method called by the external system to start a vibration.
+ *
+ * If this returns {@code SCALE_MUTE}, then the vibration should <em>not</em> play. If this
+ * returns any other scale level, then any currently playing vibration controlled by the
+ * requesting system must be muted and this vibration can begin playback.
+ *
+ * Note that the IExternalVibratorService implementation will not call mute on any currently
+ * playing external vibrations in order to avoid re-entrancy with the system on the other side.
+ *
+ * @param vibration An ExternalVibration
+ *
+ * @return {@code SCALE_MUTE} if the external vibration should not play, and any other scale
+ * level if it should.
+ */
+ int onExternalVibrationStart(in ExternalVibration vib);
+
+ /**
+ * A method called by the external system when a vibration no longer wants to play.
+ */
+ void onExternalVibrationStop(in ExternalVibration vib);
+}
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index 74d434c51781..93d6f4c12128 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -119,6 +119,23 @@ interface IStatsManager {
void removeDataFetchOperation(long configKey, in String packageName);
/**
+ * Registers the given pending intent for this packagename. This intent is invoked when the
+ * active status of any of the configs sent by this package changes and will contain a list of
+ * config ids that are currently active. It also returns the list of configs that are currently
+ * active. There can be at most one active configs changed listener per package.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ long[] setActiveConfigsChangedOperation(in IBinder intentSender, in String packageName);
+
+ /**
+ * Removes the active configs changed operation for the specified package name.
+ *
+ * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS.
+ */
+ void removeActiveConfigsChangedOperation(in String packageName);
+
+ /**
* Removes the configuration with the matching config key. No-op if this config key does not
* exist.
*
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 630bd2e509ff..d68eeeda2eb9 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -31,6 +31,7 @@ import static android.system.OsConstants.S_ISLNK;
import static android.system.OsConstants.S_ISREG;
import static android.system.OsConstants.S_IWOTH;
+import android.annotation.TestApi;
import android.content.BroadcastReceiver;
import android.content.ContentProvider;
import android.os.MessageQueue.OnFileDescriptorEventListener;
@@ -580,6 +581,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
*
* @hide
*/
+ @TestApi
public static File getFile(FileDescriptor fd) throws IOException {
try {
final String path = Os.readlink("/proc/self/fd/" + fd.getInt$());
diff --git a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
index 8d568c84b915..33795f81ded9 100644
--- a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
+++ b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
@@ -78,15 +78,6 @@ public abstract class RuntimePermissionPresenterService extends Service {
public abstract List<RuntimePermissionPresentationInfo> onGetAppPermissions(
@NonNull String packageName);
- /**
- * Revokes the permission {@code permissionName} for app {@code packageName}
- *
- * @param packageName The package for which to revoke
- * @param permissionName The permission to revoke
- */
- public abstract void onRevokeRuntimePermission(@NonNull String packageName,
- @NonNull String permissionName);
-
@Override
public final IBinder onBind(Intent intent) {
return new IRuntimePermissionPresenter.Stub() {
@@ -99,17 +90,6 @@ public abstract class RuntimePermissionPresenterService extends Service {
obtainMessage(RuntimePermissionPresenterService::getAppPermissions,
RuntimePermissionPresenterService.this, packageName, callback));
}
-
- @Override
- public void revokeRuntimePermission(String packageName, String permissionName) {
- checkNotNull(packageName, "packageName");
- checkNotNull(permissionName, "permissionName");
-
- mHandler.sendMessage(
- obtainMessage(RuntimePermissionPresenterService::onRevokeRuntimePermission,
- RuntimePermissionPresenterService.this, packageName,
- permissionName));
- }
};
}
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 8bd75d779154..8a52f1f0eec0 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -19,6 +19,7 @@ package android.provider;
import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.Activity;
import android.app.AlarmManager;
@@ -805,6 +806,7 @@ public final class CalendarContract {
*
* @hide
*/
+ @TestApi
public static final String[] SYNC_WRITABLE_COLUMNS = new String[] {
ACCOUNT_NAME,
ACCOUNT_TYPE,
@@ -1832,6 +1834,7 @@ public final class CalendarContract {
*
* @hide
*/
+ @TestApi
public static final String[] SYNC_WRITABLE_COLUMNS = new String[] {
_SYNC_ID,
DIRTY,
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 25554b937065..81e1eb99336b 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -126,6 +126,7 @@ public final class ContactsContract {
* Prefix for column names that are not visible to client apps.
* @hide
*/
+ @TestApi
public static final String HIDDEN_COLUMN_PREFIX = "x_";
/**
@@ -8444,6 +8445,7 @@ public final class ContactsContract {
* nothing will be done.
* @hide
*/
+ @TestApi
public static final String UNDEMOTE_METHOD = "undemote";
/**
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index f5c442f194ba..887175a80421 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -104,6 +104,11 @@ public final class MediaStore {
*/
public static final String VOLUME_EXTERNAL = "external";
+ /** {@hide} */ @TestApi
+ public static final String SCAN_FILE_CALL = "scan_file";
+ /** {@hide} */ @TestApi
+ public static final String SCAN_VOLUME_CALL = "scan_volume";
+
/**
* The method name used by the media scanner and mtp to tell the media provider to
* rescan and reclassify that have become unhidden because of renaming folders or
@@ -2992,6 +2997,7 @@ public final class MediaStore {
*
* @hide
*/
+ @TestApi
public static @NonNull File getVolumePath(@NonNull String volumeName)
throws FileNotFoundException {
if (TextUtils.isEmpty(volumeName)) {
@@ -3022,6 +3028,7 @@ public final class MediaStore {
*
* @hide
*/
+ @TestApi
public static @NonNull Collection<File> getVolumeScanPaths(@NonNull String volumeName)
throws FileNotFoundException {
if (TextUtils.isEmpty(volumeName)) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 852b65a05034..195e72c71e55 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8786,6 +8786,7 @@ public final class Settings {
CLONE_TO_MANAGED_PROFILE.add(LOCATION_CHANGER);
CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE);
CLONE_TO_MANAGED_PROFILE.add(LOCATION_PROVIDERS_ALLOWED);
+ CLONE_TO_MANAGED_PROFILE.add(SHOW_IME_WITH_HARD_KEYBOARD);
if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
CLONE_TO_MANAGED_PROFILE.add(DEFAULT_INPUT_METHOD);
CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS);
@@ -11722,6 +11723,7 @@ public final class Settings {
* entity_list_default (String[])
* entity_list_not_editable (String[])
* entity_list_editable (String[])
+ * lang_id_threshold_override (float)
* </pre>
*
* <p>
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 140336e93357..dce5d56e24a4 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -18,6 +18,7 @@ package android.provider;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.TestApi;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentValues;
@@ -289,6 +290,7 @@ public class VoicemailContract {
* Path to the media content file. Internal only field.
* @hide
*/
+ @TestApi
public static final String _DATA = "_data";
// Note: PHONE_ACCOUNT_* constant values are "subscription_*" due to a historic naming
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index b6788f578bd6..93189b310485 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -63,15 +63,17 @@ public final class Adjustment implements Parcelable {
/**
* Data type: ArrayList of {@link android.app.Notification.Action}.
- * Used to suggest extra actions for a notification.
+ * Used to suggest contextual actions for a notification.
+ *
+ * @see Notification.Action.Builder#setContextual(boolean)
*/
- public static final String KEY_SMART_ACTIONS = "key_smart_actions";
+ public static final String KEY_CONTEXTUAL_ACTIONS = "key_contextual_actions";
/**
* Data type: ArrayList of {@link CharSequence}.
* Used to suggest smart replies for a notification.
*/
- public static final String KEY_SMART_REPLIES = "key_smart_replies";
+ public static final String KEY_TEXT_REPLIES = "key_text_replies";
/**
* Data type: int, one of importance values e.g.
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 4052ed782671..db9351b030df 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -52,7 +52,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put("settings_mobile_network_v2", "true");
DEFAULT_FLAGS.put("settings_network_and_internet_v2", "false");
DEFAULT_FLAGS.put("settings_seamless_transfer", "false");
- DEFAULT_FLAGS.put("settings_slice_injection", "false");
+ DEFAULT_FLAGS.put("settings_slice_injection", "true");
DEFAULT_FLAGS.put("settings_systemui_theme", "true");
DEFAULT_FLAGS.put("settings_wifi_dpp", "true");
DEFAULT_FLAGS.put("settings_wifi_mac_randomization", "true");
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index f58efc900427..e3a6bd7a6949 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -26,6 +26,7 @@ import android.app.KeyguardManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.ColorSpace;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
@@ -953,6 +954,24 @@ public final class Display {
}
/**
+ * Returns the preferred wide color space of the Display.
+ * The returned wide gamut color space is based on hardware capability and
+ * is preferred by the composition pipeline.
+ * Returns null if the display doesn't support wide color gamut.
+ * {@link Display#isWideColorGamut()}.
+ */
+ @Nullable
+ public ColorSpace getPreferredWideGamutColorSpace() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ if (mDisplayInfo.isWideColorGamut()) {
+ return mGlobal.getPreferredWideGamutColorSpace();
+ }
+ return null;
+ }
+ }
+
+ /**
* Gets the supported color modes of this device.
* @hide
*/
diff --git a/core/java/android/view/textclassifier/TextClassificationConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java
index ce680ecbd119..7f928f74da19 100644
--- a/core/java/android/view/textclassifier/TextClassificationConstants.java
+++ b/core/java/android/view/textclassifier/TextClassificationConstants.java
@@ -46,6 +46,7 @@ import java.util.StringJoiner;
* entity_list_default (String[])
* entity_list_not_editable (String[])
* entity_list_editable (String[])
+ * lang_id_threshold_override (float)
* </pre>
*
* <p>
@@ -94,6 +95,8 @@ public final class TextClassificationConstants {
"in_app_conversation_action_types_default";
private static final String NOTIFICATION_CONVERSATION_ACTION_TYPES_DEFAULT =
"notification_conversation_action_types_default";
+ private static final String LANG_ID_THRESHOLD_OVERRIDE =
+ "lang_id_threshold_override";
private static final boolean LOCAL_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
private static final boolean SYSTEM_TEXT_CLASSIFIER_ENABLED_DEFAULT = true;
@@ -106,8 +109,8 @@ public final class TextClassificationConstants {
private static final int CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
private static final int GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT = 100 * 1000;
private static final int GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT = 100;
- private static final String ENTITY_LIST_DELIMITER = ":";
- private static final String ENTITY_LIST_DEFAULT_VALUE = new StringJoiner(ENTITY_LIST_DELIMITER)
+ private static final String STRING_LIST_DELIMITER = ":";
+ private static final String ENTITY_LIST_DEFAULT_VALUE = new StringJoiner(STRING_LIST_DELIMITER)
.add(TextClassifier.TYPE_ADDRESS)
.add(TextClassifier.TYPE_EMAIL)
.add(TextClassifier.TYPE_PHONE)
@@ -116,7 +119,7 @@ public final class TextClassificationConstants {
.add(TextClassifier.TYPE_DATE_TIME)
.add(TextClassifier.TYPE_FLIGHT_NUMBER).toString();
private static final String CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES =
- new StringJoiner(ENTITY_LIST_DELIMITER)
+ new StringJoiner(STRING_LIST_DELIMITER)
.add(ConversationAction.TYPE_TEXT_REPLY)
.add(ConversationAction.TYPE_CREATE_REMINDER)
.add(ConversationAction.TYPE_CALL_PHONE)
@@ -127,6 +130,13 @@ public final class TextClassificationConstants {
.add(ConversationAction.TYPE_VIEW_CALENDAR)
.add(ConversationAction.TYPE_VIEW_MAP)
.toString();
+ /**
+ * < 0 : Not set. Use value from LangId model.
+ * 0 - 1: Override value in LangId model.
+ * > 1 : Effectively turns off the foreign language detection. Scores should never be > 1.
+ * @see EntityConfidence
+ */
+ private static final float LANG_ID_THRESHOLD_OVERRIDE_DEFAULT = -1f;
private final boolean mSystemTextClassifierEnabled;
private final boolean mLocalTextClassifierEnabled;
@@ -144,6 +154,7 @@ public final class TextClassificationConstants {
private final List<String> mEntityListEditable;
private final List<String> mInAppConversationActionTypesDefault;
private final List<String> mNotificationConversationActionTypesDefault;
+ private final float mLangIdThresholdOverride;
private TextClassificationConstants(@Nullable String settings) {
final KeyValueListParser parser = new KeyValueListParser(',');
@@ -186,21 +197,24 @@ public final class TextClassificationConstants {
mGenerateLinksLogSampleRate = parser.getInt(
GENERATE_LINKS_LOG_SAMPLE_RATE,
GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT);
- mEntityListDefault = parseEntityList(parser.getString(
+ mEntityListDefault = parseStringList(parser.getString(
ENTITY_LIST_DEFAULT,
ENTITY_LIST_DEFAULT_VALUE));
- mEntityListNotEditable = parseEntityList(parser.getString(
+ mEntityListNotEditable = parseStringList(parser.getString(
ENTITY_LIST_NOT_EDITABLE,
ENTITY_LIST_DEFAULT_VALUE));
- mEntityListEditable = parseEntityList(parser.getString(
+ mEntityListEditable = parseStringList(parser.getString(
ENTITY_LIST_EDITABLE,
ENTITY_LIST_DEFAULT_VALUE));
- mInAppConversationActionTypesDefault = parseEntityList(parser.getString(
+ mInAppConversationActionTypesDefault = parseStringList(parser.getString(
IN_APP_CONVERSATION_ACTION_TYPES_DEFAULT,
CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES));
- mNotificationConversationActionTypesDefault = parseEntityList(parser.getString(
+ mNotificationConversationActionTypesDefault = parseStringList(parser.getString(
NOTIFICATION_CONVERSATION_ACTION_TYPES_DEFAULT,
CONVERSATION_ACTIONS_TYPES_DEFAULT_VALUES));
+ mLangIdThresholdOverride = parser.getFloat(
+ LANG_ID_THRESHOLD_OVERRIDE,
+ LANG_ID_THRESHOLD_OVERRIDE_DEFAULT);
}
/** Load from a settings string. */
@@ -272,8 +286,12 @@ public final class TextClassificationConstants {
return mNotificationConversationActionTypesDefault;
}
- private static List<String> parseEntityList(String listStr) {
- return Collections.unmodifiableList(Arrays.asList(listStr.split(ENTITY_LIST_DELIMITER)));
+ public float getLangIdThresholdOverride() {
+ return mLangIdThresholdOverride;
+ }
+
+ private static List<String> parseStringList(String listStr) {
+ return Collections.unmodifiableList(Arrays.asList(listStr.split(STRING_LIST_DELIMITER)));
}
void dump(IndentingPrintWriter pw) {
@@ -296,6 +314,7 @@ public final class TextClassificationConstants {
pw.printPair("getInAppConversationActionTypes", mInAppConversationActionTypesDefault);
pw.printPair("getNotificationConversationActionTypes",
mNotificationConversationActionTypesDefault);
+ pw.printPair("getLangIdThresholdOverride", mLangIdThresholdOverride);
pw.decreaseIndent();
pw.println();
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index a5b7c621be38..7782079213e7 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -567,8 +567,9 @@ public final class TextClassifierImpl implements TextClassifier {
}
}
- // TODO: Make this configurable.
- final float foreignTextThreshold = typeCount == 0 ? 0.5f : 0.7f;
+ final float foreignTextThreshold = mSettings.getLangIdThresholdOverride() >= 0
+ ? mSettings.getLangIdThresholdOverride()
+ : 0.5f /* TODO: Load this from the langId model. */;
boolean isPrimaryAction = true;
final ArrayList<Intent> sourceIntents = new ArrayList<>();
for (LabeledIntent labeledIntent : IntentFactory.create(
@@ -602,6 +603,10 @@ public final class TextClassifierImpl implements TextClassifier {
}
private boolean isForeignText(String text, float threshold) {
+ if (threshold > 1) {
+ return false;
+ }
+
// TODO: Revisit this algorithm.
try {
final LangIdModel.LanguageResult[] langResults = getLangIdImpl().detectLanguages(text);
diff --git a/core/java/android/view/textclassifier/TextLanguage.java b/core/java/android/view/textclassifier/TextLanguage.java
index b1609fcfe56a..735c3eba226e 100644
--- a/core/java/android/view/textclassifier/TextLanguage.java
+++ b/core/java/android/view/textclassifier/TextLanguage.java
@@ -89,9 +89,10 @@ public final class TextLanguage implements Parcelable {
/**
* Returns the language locale at the specified index. Locales are ordered from high
* confidence to low confidence.
+ * <p>
+ * See {@link #getLocaleHypothesisCount()} for the number of locales available.
*
* @throws IndexOutOfBoundsException if the specified index is out of range.
- * @see #getLocaleHypothesisCount() for the number of locales available.
*/
@NonNull
public ULocale getLocale(int index) {
@@ -109,7 +110,8 @@ public final class TextLanguage implements Parcelable {
}
/**
- * Returns a bundle containing non-structured extra information about this result.
+ * Returns a bundle containing non-structured extra information about this result. What is
+ * returned in the extras is specific to the {@link TextClassifier} implementation.
*
* <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should prefer
* to hold a reference to the returned bundle rather than frequently calling this method.
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index afe467012307..5147306d277c 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -359,7 +359,7 @@ public final class Magnifier {
/**
* @return the initial width of the content magnified and copied to the magnifier, in pixels
* @see Magnifier.Builder#setSize(int, int)
- * @see Magnifier.Builder#setZoom(float)
+ * @see Magnifier.Builder#setInitialZoom(float)
*/
@Px
public int getSourceWidth() {
@@ -369,7 +369,7 @@ public final class Magnifier {
/**
* @return the initial height of the content magnified and copied to the magnifier, in pixels
* @see Magnifier.Builder#setSize(int, int)
- * @see Magnifier.Builder#setZoom(float)
+ * @see Magnifier.Builder#setInitialZoom(float)
*/
@Px
public int getSourceHeight() {
@@ -394,7 +394,7 @@ public final class Magnifier {
* If the zoom is x and the magnifier window size is (width, height), the original size
* of the content being magnified will be (width / x, height / x).
* @return the zoom applied to the content
- * @see Magnifier.Builder#setZoom(float)
+ * @see Magnifier.Builder#setInitialZoom(float)
*/
public float getZoom() {
return mZoom;
@@ -1196,10 +1196,12 @@ public final class Magnifier {
* (content_width * zoom, content_height * zoom), which will coincide with the size
* of the magnifier. A zoom of 1 will translate to no magnification (the content will
* be just copied to the magnifier with no scaling). The zoom defaults to 1.25.
+ * Note that the zoom can also be changed after the instance is built, using the
+ * {@link Magnifier#setZoom(float)} method.
* @param zoom the zoom to be set
*/
@NonNull
- public Builder setZoom(@FloatRange(from = 0f) float zoom) {
+ public Builder setInitialZoom(@FloatRange(from = 0f) float zoom) {
Preconditions.checkArgumentPositive(zoom, "Zoom should be positive");
mZoom = zoom;
return this;
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 6a28059d3fd0..943c726b173e 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -160,4 +160,9 @@ oneway interface IStatusBar
void onBiometricError(String error);
// Used to hide the biometric dialog when the AuthenticationClient is stopped
void hideBiometricDialog();
+
+ /**
+ * Notifies System UI that the display is ready to show system decorations.
+ */
+ void onDisplayReady(int displayId);
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index be127009a21d..0466aaaee9fd 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -275,6 +275,7 @@ cc_library_shared {
"libselinux",
"libandroidicu",
"libmedia",
+ "libmedia_helper",
"libmediametrics",
"libmeminfo",
"libaudioclient",
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index acb34ba3dfec..cc22ff02e338 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -669,12 +669,12 @@ namespace PaintGlue {
}
static jint getHinting(jlong paintHandle) {
- return (SkFontHinting)reinterpret_cast<Paint*>(paintHandle)->getHinting()
+ return (SkFontHinting)reinterpret_cast<Paint*>(paintHandle)->getSkFont().getHinting()
== kNo_SkFontHinting ? 0 : 1;
}
static void setHinting(jlong paintHandle, jint mode) {
- reinterpret_cast<Paint*>(paintHandle)->setHinting(
+ reinterpret_cast<Paint*>(paintHandle)->getSkFont().setHinting(
mode == 0 ? kNo_SkFontHinting : kNormal_SkFontHinting);
}
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 1065738466e7..a0d99ec95b55 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -23,6 +23,7 @@
#include "core_jni_helpers.h"
#include <utils/Log.h>
+#include <media/AudioParameter.h>
#include <media/AudioSystem.h>
#include <media/AudioTrack.h>
@@ -1311,6 +1312,33 @@ static jint android_media_AudioTrack_get_port_id(JNIEnv *env, jobject thiz) {
}
// ----------------------------------------------------------------------------
+static void android_media_AudioTrack_set_delay_padding(JNIEnv *env, jobject thiz,
+ jint delayInFrames, jint paddingInFrames) {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "AudioTrack not initialized");
+ return;
+ }
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES), (int) delayInFrames);
+ param.addInt(String8(AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES), (int) paddingInFrames);
+ lpTrack->setParameters(param.toString());
+}
+
+static void android_media_AudioTrack_set_eos(JNIEnv *env, jobject thiz) {
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "AudioTrack not initialized");
+ return;
+ }
+ AudioParameter param = AudioParameter();
+ param.addInt(String8("EOS"), 1);
+ lpTrack->setParameters(param.toString());
+}
+
+// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
// name, signature, funcPtr
@@ -1385,6 +1413,8 @@ static const JNINativeMethod gMethods[] = {
(void *)android_media_AudioTrack_get_volume_shaper_state},
{"native_setPresentation", "(II)I", (void *)android_media_AudioTrack_setPresentation},
{"native_getPortId", "()I", (void *)android_media_AudioTrack_get_port_id},
+ {"native_set_delay_padding", "(II)V", (void *)android_media_AudioTrack_set_delay_padding},
+ {"native_set_eos", "()V", (void *)android_media_AudioTrack_set_eos},
};
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 4e486630adae..4b37f13cbb33 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -423,13 +423,13 @@ bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
}
void FileDescriptorInfo::DetachSocket(fail_fn_t fail_fn) const {
- const int dev_null_fd = open("/dev/null", O_RDWR);
+ const int dev_null_fd = open("/dev/null", O_RDWR | O_CLOEXEC);
if (dev_null_fd < 0) {
fail_fn(std::string("Failed to open /dev/null: ").append(strerror(errno)));
}
- if (dup2(dev_null_fd, fd) == -1) {
- fail_fn(android::base::StringPrintf("Failed dup2 on socket descriptor %d: %s",
+ if (dup3(dev_null_fd, fd, O_CLOEXEC) == -1) {
+ fail_fn(android::base::StringPrintf("Failed dup3 on socket descriptor %d: %s",
fd,
strerror(errno)));
}
diff --git a/core/proto/android/hardware/biometrics/enums.proto b/core/proto/android/hardware/biometrics/enums.proto
new file mode 100644
index 000000000000..91f2acbbaf03
--- /dev/null
+++ b/core/proto/android/hardware/biometrics/enums.proto
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+package android.hardware.biometrics;
+
+option java_outer_classname = "BiometricsProtoEnums";
+option java_multiple_files = true;
+
+// Logging constants for <Biometric>Service and BiometricService
+
+enum ModalityEnum {
+ MODALITY_UNKNOWN = 0;
+ MODALITY_FINGERPRINT = 1; // 1 << 0
+ MODALITY_IRIS = 2; // 1 << 1
+ MODALITY_FACE = 4; // 1 << 2
+}
+
+enum ClientEnum {
+ CLIENT_UNKNOWN = 0;
+ CLIENT_KEYGUARD = 1;
+ CLIENT_BIOMETRIC_PROMPT = 2;
+ CLIENT_FINGERPRINT_MANAGER = 3; // Deprecated API before BiometricPrompt was introduced
+}
+
+enum ActionEnum {
+ ACTION_UNKNOWN = 0;
+ ACTION_ENROLL = 1;
+ ACTION_AUTHENTICATE = 2;
+ ACTION_ENUMERATE = 3;
+ ACTION_REMOVE = 4;
+} \ No newline at end of file
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index aaf6c63b2978..f3733fdb3810 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -72,6 +72,9 @@ message SecureSettingsProto {
// List of the accessibility services to which the user has granted
// permission to put the device into touch exploration mode.
optional SettingProto touch_exploration_granted_accessibility_services = 31;
+ // Settings for accessibility timeout
+ optional SettingProto non_interactive_ui_timeout_ms = 32 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto interactive_ui_timeout_ms = 33 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Accessibility accessibility = 2;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4a54bd775387..25baa921e8c9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -43,7 +43,7 @@
<protected-broadcast android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_CHANGED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_ENABLE_ROLLBACK" />
- <protected-broadcast android:name="android.intent.action.PACKAGE_ROLLBACK_EXECUTED" />
+ <protected-broadcast android:name="android.intent.action.ROLLBACK_COMMITTED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_RESTARTED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_LAUNCH" />
@@ -3329,7 +3329,7 @@
<permission android:name="com.android.permission.INSTALL_EXISTING_PACKAGES"
android:protectionLevel="signature|privileged" />
- <!-- @SystemApi Allows an application to clear user data.
+ <!-- @SystemApi @TestApi Allows an application to clear user data.
<p>Not for use by third-party applications
@hide
-->
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
index 9662182b8cf8..32bafec4081a 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
@@ -16,9 +16,7 @@
package android.view.textclassifier;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertWithMessage;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -30,6 +28,8 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class TextClassificationConstantsTest {
+ private static final float EPSILON = 0.0001f;
+
@Test
public void testLoadFromString() {
final String s = "local_textclassifier_enabled=true,"
@@ -42,26 +42,55 @@ public class TextClassificationConstantsTest {
+ "suggest_selection_max_range_length=10,"
+ "classify_text_max_range_length=11,"
+ "generate_links_max_text_length=12,"
- + "generate_links_log_sample_rate=13";
+ + "generate_links_log_sample_rate=13,"
+ + "entity_list_default=phone,"
+ + "entity_list_not_editable=address:flight,"
+ + "entity_list_editable=date:datetime,"
+ + "in_app_conversation_action_types_default=text_reply,"
+ + "notification_conversation_action_types_default=send_email:call_phone,"
+ + "lang_id_threshold_override=0.3";
final TextClassificationConstants constants =
TextClassificationConstants.loadFromString(s);
- assertTrue("local_textclassifier_enabled",
- constants.isLocalTextClassifierEnabled());
- assertTrue("system_textclassifier_enabled",
- constants.isSystemTextClassifierEnabled());
- assertTrue("model_dark_launch_enabled", constants.isModelDarkLaunchEnabled());
- assertTrue("smart_selection_enabled", constants.isSmartSelectionEnabled());
- assertTrue("smart_text_share_enabled", constants.isSmartTextShareEnabled());
- assertTrue("smart_linkify_enabled", constants.isSmartLinkifyEnabled());
- assertTrue("smart_select_animation_enabled", constants.isSmartSelectionAnimationEnabled());
- assertEquals("suggest_selection_max_range_length",
- 10, constants.getSuggestSelectionMaxRangeLength());
- assertEquals("classify_text_max_range_length",
- 11, constants.getClassifyTextMaxRangeLength());
- assertEquals("generate_links_max_text_length",
- 12, constants.getGenerateLinksMaxTextLength());
- assertEquals("generate_links_log_sample_rate",
- 13, constants.getGenerateLinksLogSampleRate());
+
+ assertWithMessage("local_textclassifier_enabled")
+ .that(constants.isLocalTextClassifierEnabled()).isTrue();
+ assertWithMessage("system_textclassifier_enabled")
+ .that(constants.isSystemTextClassifierEnabled()).isTrue();
+ assertWithMessage("model_dark_launch_enabled")
+ .that(constants.isModelDarkLaunchEnabled()).isTrue();
+ assertWithMessage("smart_selection_enabled")
+ .that(constants.isSmartSelectionEnabled()).isTrue();
+ assertWithMessage("smart_text_share_enabled")
+ .that(constants.isSmartTextShareEnabled()).isTrue();
+ assertWithMessage("smart_linkify_enabled")
+ .that(constants.isSmartLinkifyEnabled()).isTrue();
+ assertWithMessage("smart_select_animation_enabled")
+ .that(constants.isSmartSelectionAnimationEnabled()).isTrue();
+ assertWithMessage("suggest_selection_max_range_length")
+ .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(10);
+ assertWithMessage("classify_text_max_range_length")
+ .that(constants.getClassifyTextMaxRangeLength()).isEqualTo(11);
+ assertWithMessage("generate_links_max_text_length")
+ .that(constants.getGenerateLinksMaxTextLength()).isEqualTo(12);
+ assertWithMessage("generate_links_log_sample_rate")
+ .that(constants.getGenerateLinksLogSampleRate()).isEqualTo(13);
+ assertWithMessage("entity_list_default")
+ .that(constants.getEntityListDefault())
+ .containsExactly("phone");
+ assertWithMessage("entity_list_not_editable")
+ .that(constants.getEntityListNotEditable())
+ .containsExactly("address", "flight");
+ assertWithMessage("entity_list_editable")
+ .that(constants.getEntityListEditable())
+ .containsExactly("date", "datetime");
+ assertWithMessage("in_app_conversation_action_types_default")
+ .that(constants.getInAppConversationActionTypes())
+ .containsExactly("text_reply");
+ assertWithMessage("notification_conversation_action_types_default")
+ .that(constants.getNotificationConversationActionTypes())
+ .containsExactly("send_email", "call_phone");
+ assertWithMessage("lang_id_threshold_override")
+ .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(0.3f);
}
@Test
@@ -76,42 +105,102 @@ public class TextClassificationConstantsTest {
+ "suggest_selection_max_range_length=8,"
+ "classify_text_max_range_length=7,"
+ "generate_links_max_text_length=6,"
- + "generate_links_log_sample_rate=5";
+ + "generate_links_log_sample_rate=5,"
+ + "entity_list_default=email:url,"
+ + "entity_list_not_editable=date,"
+ + "entity_list_editable=flight,"
+ + "in_app_conversation_action_types_default=view_map:track_flight,"
+ + "notification_conversation_action_types_default=share_location,"
+ + "lang_id_threshold_override=2";
final TextClassificationConstants constants =
TextClassificationConstants.loadFromString(s);
- assertFalse("local_textclassifier_enabled",
- constants.isLocalTextClassifierEnabled());
- assertFalse("system_textclassifier_enabled",
- constants.isSystemTextClassifierEnabled());
- assertFalse("model_dark_launch_enabled", constants.isModelDarkLaunchEnabled());
- assertFalse("smart_selection_enabled", constants.isSmartSelectionEnabled());
- assertFalse("smart_text_share_enabled", constants.isSmartTextShareEnabled());
- assertFalse("smart_linkify_enabled", constants.isSmartLinkifyEnabled());
- assertFalse("smart_select_animation_enabled",
- constants.isSmartSelectionAnimationEnabled());
- assertEquals("suggest_selection_max_range_length",
- 8, constants.getSuggestSelectionMaxRangeLength());
- assertEquals("classify_text_max_range_length",
- 7, constants.getClassifyTextMaxRangeLength());
- assertEquals("generate_links_max_text_length",
- 6, constants.getGenerateLinksMaxTextLength());
- assertEquals("generate_links_log_sample_rate",
- 5, constants.getGenerateLinksLogSampleRate());
+
+ assertWithMessage("local_textclassifier_enabled")
+ .that(constants.isLocalTextClassifierEnabled()).isFalse();
+ assertWithMessage("system_textclassifier_enabled")
+ .that(constants.isSystemTextClassifierEnabled()).isFalse();
+ assertWithMessage("model_dark_launch_enabled")
+ .that(constants.isModelDarkLaunchEnabled()).isFalse();
+ assertWithMessage("smart_selection_enabled")
+ .that(constants.isSmartSelectionEnabled()).isFalse();
+ assertWithMessage("smart_text_share_enabled")
+ .that(constants.isSmartTextShareEnabled()).isFalse();
+ assertWithMessage("smart_linkify_enabled")
+ .that(constants.isSmartLinkifyEnabled()).isFalse();
+ assertWithMessage("smart_select_animation_enabled")
+ .that(constants.isSmartSelectionAnimationEnabled()).isFalse();
+ assertWithMessage("suggest_selection_max_range_length")
+ .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(8);
+ assertWithMessage("classify_text_max_range_length")
+ .that(constants.getClassifyTextMaxRangeLength()).isEqualTo(7);
+ assertWithMessage("generate_links_max_text_length")
+ .that(constants.getGenerateLinksMaxTextLength()).isEqualTo(6);
+ assertWithMessage("generate_links_log_sample_rate")
+ .that(constants.getGenerateLinksLogSampleRate()).isEqualTo(5);
+ assertWithMessage("entity_list_default")
+ .that(constants.getEntityListDefault())
+ .containsExactly("email", "url");
+ assertWithMessage("entity_list_not_editable")
+ .that(constants.getEntityListNotEditable())
+ .containsExactly("date");
+ assertWithMessage("entity_list_editable")
+ .that(constants.getEntityListEditable())
+ .containsExactly("flight");
+ assertWithMessage("in_app_conversation_action_types_default")
+ .that(constants.getInAppConversationActionTypes())
+ .containsExactly("view_map", "track_flight");
+ assertWithMessage("notification_conversation_action_types_default")
+ .that(constants.getNotificationConversationActionTypes())
+ .containsExactly("share_location");
+ assertWithMessage("lang_id_threshold_override")
+ .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(2f);
}
@Test
- public void testEntityListParsing() {
- final TextClassificationConstants constants = TextClassificationConstants.loadFromString(
- "entity_list_default=phone,"
- + "entity_list_not_editable=address:flight,"
- + "entity_list_editable=date:datetime");
- assertEquals(1, constants.getEntityListDefault().size());
- assertEquals("phone", constants.getEntityListDefault().get(0));
- assertEquals(2, constants.getEntityListNotEditable().size());
- assertEquals("address", constants.getEntityListNotEditable().get(0));
- assertEquals("flight", constants.getEntityListNotEditable().get(1));
- assertEquals(2, constants.getEntityListEditable().size());
- assertEquals("date", constants.getEntityListEditable().get(0));
- assertEquals("datetime", constants.getEntityListEditable().get(1));
+ public void testLoadFromString_defaultValues() {
+ final TextClassificationConstants constants =
+ TextClassificationConstants.loadFromString("");
+
+ assertWithMessage("local_textclassifier_enabled")
+ .that(constants.isLocalTextClassifierEnabled()).isTrue();
+ assertWithMessage("system_textclassifier_enabled")
+ .that(constants.isSystemTextClassifierEnabled()).isTrue();
+ assertWithMessage("model_dark_launch_enabled")
+ .that(constants.isModelDarkLaunchEnabled()).isFalse();
+ assertWithMessage("smart_selection_enabled")
+ .that(constants.isSmartSelectionEnabled()).isTrue();
+ assertWithMessage("smart_text_share_enabled")
+ .that(constants.isSmartTextShareEnabled()).isTrue();
+ assertWithMessage("smart_linkify_enabled")
+ .that(constants.isSmartLinkifyEnabled()).isTrue();
+ assertWithMessage("smart_select_animation_enabled")
+ .that(constants.isSmartSelectionAnimationEnabled()).isTrue();
+ assertWithMessage("suggest_selection_max_range_length")
+ .that(constants.getSuggestSelectionMaxRangeLength()).isEqualTo(10 * 1000);
+ assertWithMessage("classify_text_max_range_length")
+ .that(constants.getClassifyTextMaxRangeLength()).isEqualTo(10 * 1000);
+ assertWithMessage("generate_links_max_text_length")
+ .that(constants.getGenerateLinksMaxTextLength()).isEqualTo(100 * 1000);
+ assertWithMessage("generate_links_log_sample_rate")
+ .that(constants.getGenerateLinksLogSampleRate()).isEqualTo(100);
+ assertWithMessage("entity_list_default")
+ .that(constants.getEntityListDefault())
+ .containsExactly("address", "email", "url", "phone", "date", "datetime", "flight");
+ assertWithMessage("entity_list_not_editable")
+ .that(constants.getEntityListNotEditable())
+ .containsExactly("address", "email", "url", "phone", "date", "datetime", "flight");
+ assertWithMessage("entity_list_editable")
+ .that(constants.getEntityListEditable())
+ .containsExactly("address", "email", "url", "phone", "date", "datetime", "flight");
+ assertWithMessage("in_app_conversation_action_types_default")
+ .that(constants.getInAppConversationActionTypes())
+ .containsExactly("text_reply", "create_reminder", "call_phone", "open_url",
+ "send_email", "send_sms", "track_flight", "view_calendar", "view_map");
+ assertWithMessage("notification_conversation_action_types_default")
+ .that(constants.getNotificationConversationActionTypes())
+ .containsExactly("text_reply", "create_reminder", "call_phone", "open_url",
+ "send_email", "send_sms", "track_flight", "view_calendar", "view_map");
+ assertWithMessage("lang_id_threshold_override")
+ .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(-1f);
}
}
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 4755d45cd434..c9e46942a51a 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -1821,6 +1821,8 @@ public abstract class ColorSpace {
* @param cct The correlated color temperature, in Kelvin
* @return Corresponding XYZ values
* @throws IllegalArgumentException If cct is invalid
+ *
+ * @hide
*/
@NonNull
@Size(3)
@@ -1851,6 +1853,8 @@ public abstract class ColorSpace {
* @param srcWhitePoint The white point to adapt from
* @param dstWhitePoint The white point to adapt to
* @return A 3x3 matrix as a non-null array of 9 floats
+ *
+ * @hide
*/
@NonNull
@Size(9)
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 5e77fdf0a121..3440cde415d5 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -996,6 +996,50 @@ public class AudioTrack extends PlayerBase
}
/**
+ * Configures the delay and padding values for the current compressed stream playing
+ * in offload mode.
+ * This can only be used on a track successfully initialized with
+ * {@link AudioTrack.Builder#setOffloadedPlayback(boolean)}. The unit is frames, where a
+ * frame indicates the number of samples per channel, e.g. 100 frames for a stereo compressed
+ * stream corresponds to 200 decoded interleaved PCM samples.
+ * @param delayInFrames number of frames to be ignored at the beginning of the stream. A value
+ * of 0 indicates no padding is to be applied.
+ * @param paddingInFrames number of frames to be ignored at the end of the stream. A value of 0
+ * of 0 indicates no delay is to be applied.
+ */
+ public void setOffloadDelayPadding(int delayInFrames, int paddingInFrames) {
+ if (paddingInFrames < 0) {
+ throw new IllegalArgumentException("Illegal negative padding");
+ }
+ if (delayInFrames < 0) {
+ throw new IllegalArgumentException("Illegal negative delay");
+ }
+ if (!mOffloaded) {
+ throw new IllegalStateException("Illegal use of delay/padding on non-offloaded track");
+ }
+ if (mState == STATE_UNINITIALIZED) {
+ throw new IllegalStateException("Uninitialized track");
+ }
+ native_set_delay_padding(delayInFrames, paddingInFrames);
+ }
+
+ /**
+ * Declares that the last write() operation on this track provided the last buffer of this
+ * stream.
+ * After the end of stream, previously set padding and delay values are ignored.
+ * Use this method in the same thread as any write() operation.
+ */
+ public void setOffloadEndOfStream() {
+ if (!mOffloaded) {
+ throw new IllegalStateException("EOS not supported on non-offloaded track");
+ }
+ if (mState == STATE_UNINITIALIZED) {
+ throw new IllegalStateException("Uninitialized track");
+ }
+ native_set_eos();
+ }
+
+ /**
* Returns whether direct playback of an audio format with the provided attributes is
* currently supported on the system.
* <p>Direct playback means that the audio stream is not resampled or downmixed
@@ -3457,6 +3501,9 @@ public class AudioTrack extends PlayerBase
private native int native_getPortId();
+ private native void native_set_delay_padding(int delayInFrames, int paddingInFrames);
+ private native void native_set_eos();
+
//---------------------------------------------------------
// Utility methods
//------------------
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 4eed12f428bc..33e7d8ea1b94 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -335,7 +335,7 @@ public class MediaScanner implements AutoCloseable {
private final Uri mPlaylistsUri;
@UnsupportedAppUsage
private final Uri mFilesUri;
- private final Uri mFilesUriNoNotify;
+ private final Uri mFilesFullUri;
private final boolean mProcessPlaylists;
private final boolean mProcessGenres;
private int mMtpObjectHandle;
@@ -445,7 +445,11 @@ public class MediaScanner implements AutoCloseable {
mVideoUri = Video.Media.getContentUri(volumeName);
mImagesUri = Images.Media.getContentUri(volumeName);
mFilesUri = Files.getContentUri(volumeName);
- mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
+
+ Uri filesFullUri = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
+ filesFullUri = MediaStore.setIncludePending(filesFullUri);
+ filesFullUri = MediaStore.setIncludeTrashed(filesFullUri);
+ mFilesFullUri = filesFullUri;
if (!volumeName.equals("internal")) {
// we only support playlists on external media
@@ -1625,7 +1629,7 @@ public class MediaScanner implements AutoCloseable {
try {
where = Files.FileColumns.DATA + "=?";
selectionArgs = new String[] { path };
- c = mMediaProvider.query(mFilesUriNoNotify, FILES_PRESCAN_PROJECTION,
+ c = mMediaProvider.query(mFilesFullUri, FILES_PRESCAN_PROJECTION,
where, selectionArgs, null, null);
if (c != null && c.moveToFirst()) {
long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index a45aa90f5f19..417a427b6c7c 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -405,6 +405,11 @@ static void ImageReader_init(JNIEnv* env, jobject thiz, jobject weakThiz, jint w
nativeFormat, consumerUsage);
return;
}
+
+ if (consumerUsage & GRALLOC_USAGE_PROTECTED) {
+ gbConsumer->setConsumerIsProtected(true);
+ }
+
ctx->setBufferConsumer(bufferConsumer);
bufferConsumer->setName(consumerName);
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 5fae9d5a7974..3156732ef02b 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -47,32 +47,13 @@ using Transaction = SurfaceComposerClient::Transaction;
static bool getWideColorSupport(const sp<SurfaceControl>& surfaceControl) {
sp<SurfaceComposerClient> client = surfaceControl->getClient();
sp<IBinder> display(client->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
-
- Vector<ui::ColorMode> colorModes;
- status_t err = client->getDisplayColorModes(display, &colorModes);
+ bool isWideColorDisplay = false;
+ status_t err = client->isWideColorDisplay(display, &isWideColorDisplay);
if (err) {
ALOGE("unable to get wide color support");
return false;
}
-
- bool wideColorBoardConfig =
- getBool<ISurfaceFlingerConfigs,
- &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
-
- for (android::ui::ColorMode colorMode : colorModes) {
- switch (colorMode) {
- case ui::ColorMode::DISPLAY_P3:
- case ui::ColorMode::ADOBE_RGB:
- case ui::ColorMode::DCI_P3:
- if (wideColorBoardConfig) {
- return true;
- }
- break;
- default:
- break;
- }
- }
- return false;
+ return isWideColorDisplay;
}
static bool getHdrSupport(const sp<SurfaceControl>& surfaceControl) {
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 83084c519f19..7eaf04bfb775 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -17,7 +17,6 @@
package com.android.captiveportallogin;
import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_PROBE_SPEC;
-import static android.net.captiveportal.CaptivePortalProbeSpec.HTTP_LOCATION_HEADER_NAME;
import android.app.Activity;
import android.app.AlertDialog;
@@ -40,8 +39,6 @@ import android.net.http.SslError;
import android.net.wifi.WifiInfo;
import android.os.Build;
import android.os.Bundle;
-import android.provider.Settings;
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -61,16 +58,17 @@ import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
+import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
-import java.lang.InterruptedException;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -81,6 +79,7 @@ public class CaptivePortalLoginActivity extends Activity {
private static final boolean VDBG = false;
private static final int SOCKET_TIMEOUT_MS = 10000;
+ public static final String HTTP_LOCATION_HEADER_NAME = "Location";
private enum Result {
DISMISSED(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_DISMISSED),
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index f346b00f85b8..ce58d4ea84aa 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -230,10 +230,10 @@ public class Assistant extends NotificationAssistantService {
Bundle signals = new Bundle();
if (!smartActions.isEmpty()) {
- signals.putParcelableArrayList(Adjustment.KEY_SMART_ACTIONS, smartActions);
+ signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, smartActions);
}
if (!smartReplies.isEmpty()) {
- signals.putCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES, smartReplies);
+ signals.putCharSequenceArrayList(Adjustment.KEY_TEXT_REPLIES, smartReplies);
}
if (mSettings.mNewInterruptionModel) {
if (mNotificationCategorizer.shouldSilence(entry)) {
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index a2da0a079550..9b0d896e483e 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -21,6 +21,7 @@ java_library {
installable: true,
srcs: [
"src/**/*.java",
+ ":framework-networkstack-shared-srcs",
":services-networkstack-shared-srcs",
],
static_libs: [
diff --git a/packages/NetworkStack/TEST_MAPPING b/packages/NetworkStack/TEST_MAPPING
new file mode 100644
index 000000000000..55ba5916b7d8
--- /dev/null
+++ b/packages/NetworkStack/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "postsubmit": [
+ {
+ "name": "NetworkStackTests"
+ }
+ ]
+} \ No newline at end of file
diff --git a/packages/NetworkStack/src/android/net/apf/ApfFilter.java b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
index 50c4dfc8d700..08452bbbe433 100644
--- a/packages/NetworkStack/src/android/net/apf/ApfFilter.java
+++ b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
@@ -26,11 +26,6 @@ import static android.system.OsConstants.IPPROTO_ICMPV6;
import static android.system.OsConstants.IPPROTO_UDP;
import static android.system.OsConstants.SOCK_RAW;
-import static com.android.internal.util.BitUtils.bytesToBEInt;
-import static com.android.internal.util.BitUtils.getUint16;
-import static com.android.internal.util.BitUtils.getUint32;
-import static com.android.internal.util.BitUtils.getUint8;
-import static com.android.internal.util.BitUtils.uint32;
import static com.android.server.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
import static com.android.server.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
@@ -1586,6 +1581,29 @@ public class ApfFilter {
// TODO: move to android.net.NetworkUtils
@VisibleForTesting
public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
- return bytesToBEInt(addrBytes) | (int) (uint32(-1) >>> prefixLength);
+ return bytesToBEInt(addrBytes) | (int) (Integer.toUnsignedLong(-1) >>> prefixLength);
+ }
+
+ private static int uint8(byte b) {
+ return b & 0xff;
+ }
+
+ private static int getUint16(ByteBuffer buffer, int position) {
+ return buffer.getShort(position) & 0xffff;
+ }
+
+ private static long getUint32(ByteBuffer buffer, int position) {
+ return Integer.toUnsignedLong(buffer.getInt(position));
+ }
+
+ private static int getUint8(ByteBuffer buffer, int position) {
+ return uint8(buffer.get(position));
+ }
+
+ private static int bytesToBEInt(byte[] bytes) {
+ return (uint8(bytes[0]) << 24)
+ + (uint8(bytes[1]) << 16)
+ + (uint8(bytes[2]) << 8)
+ + (uint8(bytes[3]));
}
}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
index 04ac9a301813..12eecc070a06 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
@@ -40,6 +40,8 @@ import static android.system.OsConstants.SO_BROADCAST;
import static android.system.OsConstants.SO_RCVBUF;
import static android.system.OsConstants.SO_REUSEADDR;
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
+
import android.content.Context;
import android.net.DhcpResults;
import android.net.NetworkUtils;
@@ -328,7 +330,7 @@ public class DhcpClient extends StateMachine {
Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_REUSEADDR, 1);
Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_BROADCAST, 1);
Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_RCVBUF, 0);
- Os.bind(mUdpSock, Inet4Address.ANY, DhcpPacket.DHCP_CLIENT);
+ Os.bind(mUdpSock, IPV4_ADDR_ANY, DhcpPacket.DHCP_CLIENT);
} catch(SocketException|ErrnoException e) {
Log.e(TAG, "Error creating UDP socket", e);
return false;
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java b/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java
index 0d298de4f5f8..0a15cd7d3bd9 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpLeaseRepository.java
@@ -16,12 +16,13 @@
package android.net.dhcp;
-import static android.net.NetworkUtils.inet4AddressToIntHTH;
-import static android.net.NetworkUtils.intToInet4AddressHTH;
-import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTH;
import static android.net.dhcp.DhcpLease.EXPIRATION_NEVER;
import static android.net.dhcp.DhcpLease.inet4AddrToString;
+import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
+import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
+import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH;
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_BITS;
import static java.lang.Math.min;
@@ -201,7 +202,7 @@ class DhcpLeaseRepository {
private static boolean isIpAddrOutsidePrefix(@NonNull IpPrefix prefix,
@Nullable Inet4Address addr) {
- return addr != null && !addr.equals(Inet4Address.ANY) && !prefix.contains(addr);
+ return addr != null && !addr.equals(IPV4_ADDR_ANY) && !prefix.contains(addr);
}
@Nullable
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java
index ce8b7e78d0f8..d7ff98b1f501 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java
@@ -1,10 +1,13 @@
package android.net.dhcp;
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ALL;
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
+
import android.annotation.Nullable;
import android.net.DhcpResults;
import android.net.LinkAddress;
-import android.net.NetworkUtils;
import android.net.metrics.DhcpErrorEvent;
+import android.net.shared.Inet4AddressUtils;
import android.os.Build;
import android.os.SystemProperties;
import android.system.OsConstants;
@@ -43,8 +46,8 @@ public abstract class DhcpPacket {
public static final int MINIMUM_LEASE = 60;
public static final int INFINITE_LEASE = (int) 0xffffffff;
- public static final Inet4Address INADDR_ANY = (Inet4Address) Inet4Address.ANY;
- public static final Inet4Address INADDR_BROADCAST = (Inet4Address) Inet4Address.ALL;
+ public static final Inet4Address INADDR_ANY = IPV4_ADDR_ANY;
+ public static final Inet4Address INADDR_BROADCAST = IPV4_ADDR_ALL;
public static final byte[] ETHER_BROADCAST = new byte[] {
(byte) 0xff, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff,
@@ -1212,9 +1215,9 @@ public abstract class DhcpPacket {
*/
public DhcpResults toDhcpResults() {
Inet4Address ipAddress = mYourIp;
- if (ipAddress.equals(Inet4Address.ANY)) {
+ if (ipAddress.equals(IPV4_ADDR_ANY)) {
ipAddress = mClientIp;
- if (ipAddress.equals(Inet4Address.ANY)) {
+ if (ipAddress.equals(IPV4_ADDR_ANY)) {
return null;
}
}
@@ -1222,13 +1225,13 @@ public abstract class DhcpPacket {
int prefixLength;
if (mSubnetMask != null) {
try {
- prefixLength = NetworkUtils.netmaskToPrefixLength(mSubnetMask);
+ prefixLength = Inet4AddressUtils.netmaskToPrefixLength(mSubnetMask);
} catch (IllegalArgumentException e) {
// Non-contiguous netmask.
return null;
}
} else {
- prefixLength = NetworkUtils.getImplicitNetmask(ipAddress);
+ prefixLength = Inet4AddressUtils.getImplicitNetmask(ipAddress);
}
DhcpResults results = new DhcpResults();
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
index 7b112dfc125c..beabd3eb3152 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
@@ -16,8 +16,6 @@
package android.net.dhcp;
-import static android.net.NetworkUtils.getBroadcastAddress;
-import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
import static android.net.TrafficStats.TAG_SYSTEM_DHCP_SERVER;
import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME;
@@ -25,6 +23,8 @@ import static android.net.dhcp.DhcpPacket.DHCP_SERVER;
import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
import static android.net.dhcp.IDhcpServer.STATUS_INVALID_ARGUMENT;
import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
+import static android.net.shared.Inet4AddressUtils.getBroadcastAddress;
+import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.IPPROTO_UDP;
import static android.system.OsConstants.SOCK_DGRAM;
@@ -33,6 +33,8 @@ import static android.system.OsConstants.SO_BROADCAST;
import static android.system.OsConstants.SO_REUSEADDR;
import static com.android.server.util.NetworkStackConstants.INFINITE_LEASE;
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ALL;
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission;
import static java.lang.Integer.toUnsignedLong;
@@ -434,7 +436,7 @@ public class DhcpServer extends IDhcpServer.Stub {
if (!isEmpty(request.mRelayIp)) {
return request.mRelayIp;
} else if (broadcastFlag) {
- return (Inet4Address) Inet4Address.ALL;
+ return IPV4_ADDR_ALL;
} else if (!isEmpty(request.mClientIp)) {
return request.mClientIp;
} else {
@@ -517,7 +519,7 @@ public class DhcpServer extends IDhcpServer.Stub {
request.mRelayIp, request.mClientMac, true /* broadcast */, message);
final Inet4Address dst = isEmpty(request.mRelayIp)
- ? (Inet4Address) Inet4Address.ALL
+ ? IPV4_ADDR_ALL
: request.mRelayIp;
return transmitPacket(nakPacket, DhcpNakPacket.class.getSimpleName(), dst);
}
@@ -598,7 +600,7 @@ public class DhcpServer extends IDhcpServer.Stub {
}
private static boolean isEmpty(@Nullable Inet4Address address) {
- return address == null || Inet4Address.ANY.equals(address);
+ return address == null || IPV4_ADDR_ANY.equals(address);
}
private class PacketListener extends DhcpPacketListener {
@@ -632,7 +634,7 @@ public class DhcpServer extends IDhcpServer.Stub {
SocketUtils.bindSocketToInterface(mSocket, mIfName);
Os.setsockoptInt(mSocket, SOL_SOCKET, SO_REUSEADDR, 1);
Os.setsockoptInt(mSocket, SOL_SOCKET, SO_BROADCAST, 1);
- Os.bind(mSocket, Inet4Address.ANY, DHCP_SERVER);
+ Os.bind(mSocket, IPV4_ADDR_ANY, DHCP_SERVER);
return mSocket;
} catch (IOException | ErrnoException e) {
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java
index 868f3bed4eed..31ce95b11ba9 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpServingParams.java
@@ -16,8 +16,8 @@
package android.net.dhcp;
-import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
-import static android.net.NetworkUtils.intToInet4AddressHTH;
+import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
+import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
import static com.android.server.util.NetworkStackConstants.INFINITE_LEASE;
import static com.android.server.util.NetworkStackConstants.IPV4_MAX_MTU;
@@ -29,7 +29,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.IpPrefix;
import android.net.LinkAddress;
-import android.net.NetworkUtils;
+import android.net.shared.Inet4AddressUtils;
import android.util.ArraySet;
import java.net.Inet4Address;
@@ -164,7 +164,8 @@ public class DhcpServingParams {
*/
@NonNull
public Inet4Address getBroadcastAddress() {
- return NetworkUtils.getBroadcastAddress(getServerInet4Addr(), serverAddr.getPrefixLength());
+ return Inet4AddressUtils.getBroadcastAddress(
+ getServerInet4Addr(), serverAddr.getPrefixLength());
}
/**
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index ad7f85d0a30a..f20e01636d72 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -29,7 +29,6 @@ import android.net.INetd;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
-import android.net.Network;
import android.net.ProvisioningConfigurationParcelable;
import android.net.ProxyInfo;
import android.net.ProxyInfoParcelable;
@@ -1000,7 +999,9 @@ public class IpClient extends StateMachine {
// mDhcpResults is never shared with any other owner so we don't have
// to worry about concurrent modification.
if (mDhcpResults != null) {
- for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) {
+ final List<RouteInfo> routes =
+ mDhcpResults.toStaticIpConfiguration().getRoutes(mInterfaceName);
+ for (RouteInfo route : routes) {
newLp.addRoute(route);
}
addAllReachableDnsServers(newLp, mDhcpResults.dnsServers);
diff --git a/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java b/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java
index eb993a4243a9..2e6ff243a628 100644
--- a/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java
+++ b/packages/NetworkStack/src/android/net/ip/IpNeighborMonitor.java
@@ -36,8 +36,6 @@ import android.system.Os;
import android.system.OsConstants;
import android.util.Log;
-import com.android.internal.util.BitUtils;
-
import libcore.io.IoUtils;
import java.io.FileDescriptor;
@@ -186,7 +184,7 @@ public class IpNeighborMonitor extends PacketReader {
final int srcPortId = nlMsg.getHeader().nlmsg_pid;
if (srcPortId != 0) {
- mLog.e("non-kernel source portId: " + BitUtils.uint32(srcPortId));
+ mLog.e("non-kernel source portId: " + Integer.toUnsignedLong(srcPortId));
break;
}
diff --git a/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java b/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java
index 761db6822fb4..76a03387a12d 100644
--- a/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java
+++ b/packages/NetworkStack/src/android/net/ip/IpReachabilityMonitor.java
@@ -31,15 +31,15 @@ import android.net.metrics.IpReachabilityEvent;
import android.net.netlink.StructNdMsg;
import android.net.util.InterfaceParams;
import android.net.util.SharedLog;
+import android.os.ConditionVariable;
import android.os.Handler;
+import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.DumpUtils;
-import com.android.internal.util.DumpUtils.Dump;
import java.io.PrintWriter;
import java.net.Inet6Address;
@@ -215,15 +215,20 @@ public class IpReachabilityMonitor {
}
public void dump(PrintWriter pw) {
- DumpUtils.dumpAsync(
- mIpNeighborMonitor.getHandler(),
- new Dump() {
- @Override
- public void dump(PrintWriter pw, String prefix) {
- pw.println(describeWatchList("\n"));
- }
- },
- pw, "", 1000);
+ if (Looper.myLooper() == mIpNeighborMonitor.getHandler().getLooper()) {
+ pw.println(describeWatchList("\n"));
+ return;
+ }
+
+ final ConditionVariable cv = new ConditionVariable(false);
+ mIpNeighborMonitor.getHandler().post(() -> {
+ pw.println(describeWatchList("\n"));
+ cv.open();
+ });
+
+ if (!cv.block(1000)) {
+ pw.println("Timed out waiting for IpReachabilityMonitor dump");
+ }
}
private String describeWatchList() { return describeWatchList(" "); }
diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
new file mode 100644
index 000000000000..6dcf0c0d1626
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+/**
+ * Collection of utilities for the network stack.
+ */
+public class NetworkStackUtils {
+
+ /**
+ * @return True if the array is null or 0-length.
+ */
+ public static <T> boolean isEmpty(T[] array) {
+ return array == null || array.length == 0;
+ }
+}
diff --git a/packages/NetworkStack/src/com/android/server/NetworkObserver.java b/packages/NetworkStack/src/com/android/server/NetworkObserver.java
new file mode 100644
index 000000000000..d3b40a67633d
--- /dev/null
+++ b/packages/NetworkStack/src/com/android/server/NetworkObserver.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.net.LinkAddress;
+
+/**
+ * Observer for network events, to use with {@link NetworkObserverRegistry}.
+ */
+public interface NetworkObserver {
+
+ /**
+ * @see android.net.INetdUnsolicitedEventListener#onInterfaceChanged(java.lang.String, boolean)
+ */
+ default void onInterfaceChanged(String ifName, boolean up) {}
+
+ /**
+ * @see android.net.INetdUnsolicitedEventListener#onInterfaceRemoved(String)
+ */
+ default void onInterfaceRemoved(String ifName) {}
+
+ /**
+ * @see android.net.INetdUnsolicitedEventListener
+ * #onInterfaceAddressUpdated(String, String, int, int)
+ */
+ default void onInterfaceAddressUpdated(LinkAddress address, String ifName) {}
+
+ /**
+ * @see android.net.INetdUnsolicitedEventListener
+ * #onInterfaceAddressRemoved(String, String, int, int)
+ */
+ default void onInterfaceAddressRemoved(LinkAddress address, String ifName) {}
+
+ /**
+ * @see android.net.INetdUnsolicitedEventListener#onInterfaceLinkStateChanged(String, boolean)
+ */
+ default void onInterfaceLinkStateChanged(String ifName, boolean up) {}
+
+ /**
+ * @see android.net.INetdUnsolicitedEventListener#onInterfaceAdded(String)
+ */
+ default void onInterfaceAdded(String ifName) {}
+
+ /**
+ * @see android.net.INetdUnsolicitedEventListener
+ * #onInterfaceClassActivityChanged(boolean, int, long, int)
+ */
+ default void onInterfaceClassActivityChanged(
+ boolean isActive, int label, long timestamp, int uid) {}
+
+ /**
+ * @see android.net.INetdUnsolicitedEventListener#onQuotaLimitReached(String, String)
+ */
+ default void onQuotaLimitReached(String alertName, String ifName) {}
+
+ /**
+ * @see android.net.INetdUnsolicitedEventListener
+ * #onInterfaceDnsServerInfo(String, long, String[])
+ */
+ default void onInterfaceDnsServerInfo(String ifName, long lifetime, String[] servers) {}
+
+ /**
+ * @see android.net.INetdUnsolicitedEventListener
+ * #onRouteChanged(boolean, String, String, String)
+ */
+ default void onRouteUpdated(String route, String gateway, String ifName) {}
+
+ /**
+ * @see android.net.INetdUnsolicitedEventListener
+ * #onRouteChanged(boolean, String, String, String)
+ */
+ default void onRouteRemoved(String route, String gateway, String ifName) {}
+}
diff --git a/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java b/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java
new file mode 100644
index 000000000000..14e6c5fdadb9
--- /dev/null
+++ b/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server;
+
+import android.annotation.NonNull;
+import android.net.INetd;
+import android.net.INetdUnsolicitedEventListener;
+import android.net.LinkAddress;
+import android.os.Handler;
+import android.os.RemoteException;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A class for reporting network events to clients.
+ *
+ * Implements INetdUnsolicitedEventListener and registers with netd, and relays those events to
+ * all INetworkManagementEventObserver objects that have registered with it.
+ */
+public class NetworkObserverRegistry extends INetdUnsolicitedEventListener.Stub {
+
+ /**
+ * Constructs a new NetworkObserverRegistry.
+ *
+ * <p>Only one registry should be used per process since netd will silently ignore multiple
+ * registrations from the same process.
+ */
+ NetworkObserverRegistry() {}
+
+ /**
+ * Start listening for Netd events.
+ *
+ * <p>This should be called before allowing any observer to be registered.
+ */
+ void register(@NonNull INetd netd) throws RemoteException {
+ netd.registerUnsolicitedEventListener(this);
+ }
+
+ private final ConcurrentHashMap<NetworkObserver, Handler> mObservers =
+ new ConcurrentHashMap<>();
+
+ /**
+ * Registers the specified observer and start sending callbacks to it.
+ * This method may be called on any thread.
+ */
+ public void registerObserver(@NonNull NetworkObserver observer, @NonNull Handler handler) {
+ mObservers.put(observer, handler);
+ }
+
+ /**
+ * Unregisters the specified observer and stop sending callbacks to it.
+ * This method may be called on any thread.
+ */
+ public void unregisterObserver(@NonNull NetworkObserver observer) {
+ mObservers.remove(observer);
+ }
+
+ @FunctionalInterface
+ private interface NetworkObserverEventCallback {
+ void sendCallback(NetworkObserver o);
+ }
+
+ private void invokeForAllObservers(@NonNull final NetworkObserverEventCallback callback) {
+ // ConcurrentHashMap#entrySet is weakly consistent: observers that were in the map before
+ // creation will be processed, those added during traversal may or may not.
+ for (Map.Entry<NetworkObserver, Handler> entry : mObservers.entrySet()) {
+ final NetworkObserver observer = entry.getKey();
+ entry.getValue().post(() -> callback.sendCallback(observer));
+ }
+ }
+
+ @Override
+ public void onInterfaceClassActivityChanged(boolean isActive,
+ int label, long timestamp, int uid) {
+ invokeForAllObservers(o -> o.onInterfaceClassActivityChanged(
+ isActive, label, timestamp, uid));
+ }
+
+ /**
+ * Notify our observers of a limit reached.
+ */
+ @Override
+ public void onQuotaLimitReached(String alertName, String ifName) {
+ invokeForAllObservers(o -> o.onQuotaLimitReached(alertName, ifName));
+ }
+
+ @Override
+ public void onInterfaceDnsServerInfo(String ifName, long lifetime, String[] servers) {
+ invokeForAllObservers(o -> o.onInterfaceDnsServerInfo(ifName, lifetime, servers));
+ }
+
+ @Override
+ public void onInterfaceAddressUpdated(String addr, String ifName, int flags, int scope) {
+ final LinkAddress address = new LinkAddress(addr, flags, scope);
+ invokeForAllObservers(o -> o.onInterfaceAddressUpdated(address, ifName));
+ }
+
+ @Override
+ public void onInterfaceAddressRemoved(String addr,
+ String ifName, int flags, int scope) {
+ final LinkAddress address = new LinkAddress(addr, flags, scope);
+ invokeForAllObservers(o -> o.onInterfaceAddressRemoved(address, ifName));
+ }
+
+ @Override
+ public void onInterfaceAdded(String ifName) {
+ invokeForAllObservers(o -> o.onInterfaceAdded(ifName));
+ }
+
+ @Override
+ public void onInterfaceRemoved(String ifName) {
+ invokeForAllObservers(o -> o.onInterfaceRemoved(ifName));
+ }
+
+ @Override
+ public void onInterfaceChanged(String ifName, boolean up) {
+ invokeForAllObservers(o -> o.onInterfaceChanged(ifName, up));
+ }
+
+ @Override
+ public void onInterfaceLinkStateChanged(String ifName, boolean up) {
+ invokeForAllObservers(o -> o.onInterfaceLinkStateChanged(ifName, up));
+ }
+
+ @Override
+ public void onRouteChanged(boolean updated, String route, String gateway, String ifName) {
+ if (updated) {
+ invokeForAllObservers(o -> o.onRouteUpdated(route, gateway, ifName));
+ } else {
+ invokeForAllObservers(o -> o.onRouteRemoved(route, gateway, ifName));
+ }
+ }
+
+ @Override
+ public void onStrictCleartextDetected(int uid, String hex) {}
+}
diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
index 4080ddf9e73f..631ee453671a 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
@@ -29,6 +29,7 @@ import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
+import android.net.INetd;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkStackConnector;
@@ -65,6 +66,7 @@ import java.util.Iterator;
*/
public class NetworkStackService extends Service {
private static final String TAG = NetworkStackService.class.getSimpleName();
+ private static NetworkStackConnector sConnector;
/**
* Create a binder connector for the system server to communicate with the network stack.
@@ -72,8 +74,11 @@ public class NetworkStackService extends Service {
* <p>On platforms where the network stack runs in the system server process, this method may
* be called directly instead of obtaining the connector by binding to the service.
*/
- public static IBinder makeConnector(Context context) {
- return new NetworkStackConnector(context);
+ public static synchronized IBinder makeConnector(Context context) {
+ if (sConnector == null) {
+ sConnector = new NetworkStackConnector(context);
+ }
+ return sConnector;
}
@NonNull
@@ -85,6 +90,8 @@ public class NetworkStackService extends Service {
private static class NetworkStackConnector extends INetworkStackConnector.Stub {
private static final int NUM_VALIDATION_LOG_LINES = 20;
private final Context mContext;
+ private final INetd mNetd;
+ private final NetworkObserverRegistry mObserverRegistry;
private final ConnectivityManager mCm;
@GuardedBy("mIpClients")
private final ArrayList<WeakReference<IpClient>> mIpClients = new ArrayList<>();
@@ -106,7 +113,11 @@ public class NetworkStackService extends Service {
NetworkStackConnector(Context context) {
mContext = context;
+ mNetd = (INetd) context.getSystemService(Context.NETD_SERVICE);
+ mObserverRegistry = new NetworkObserverRegistry();
mCm = context.getSystemService(ConnectivityManager.class);
+
+ // TODO: call mObserverRegistry here after adding sepolicy changes
}
@NonNull
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index 6b31b82ec3cc..96eaa505389d 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -31,6 +31,7 @@ import static android.net.metrics.ValidationProbeEvent.DNS_FAILURE;
import static android.net.metrics.ValidationProbeEvent.DNS_SUCCESS;
import static android.net.metrics.ValidationProbeEvent.PROBE_FALLBACK;
import static android.net.metrics.ValidationProbeEvent.PROBE_PRIVDNS;
+import static android.net.util.NetworkStackUtils.isEmpty;
import android.annotation.Nullable;
import android.app.PendingIntent;
@@ -80,7 +81,6 @@ import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.RingBufferIndices;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
@@ -93,6 +93,7 @@ import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
@@ -1146,7 +1147,10 @@ public class NetworkMonitor extends StateMachine {
return null;
}
- return CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs(settingsValue);
+ final Collection<CaptivePortalProbeSpec> specs =
+ CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs(settingsValue);
+ final CaptivePortalProbeSpec[] specsArray = new CaptivePortalProbeSpec[specs.size()];
+ return specs.toArray(specsArray);
} catch (Exception e) {
// Don't let a misconfiguration bootloop the system.
Log.e(TAG, "Error parsing configured fallback probe specs", e);
@@ -1169,7 +1173,7 @@ public class NetworkMonitor extends StateMachine {
}
private CaptivePortalProbeSpec nextFallbackSpec() {
- if (ArrayUtils.isEmpty(mCaptivePortalFallbackSpecs)) {
+ if (isEmpty(mCaptivePortalFallbackSpecs)) {
return null;
}
// Randomly change spec without memory. Also randomize the first attempt.
diff --git a/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java b/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java
index eedaf30c055f..804765e33a87 100644
--- a/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java
+++ b/packages/NetworkStack/src/com/android/server/util/NetworkStackConstants.java
@@ -16,6 +16,10 @@
package com.android.server.util;
+import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
+
+import java.net.Inet4Address;
+
/**
* Network constants used by the network stack.
*/
@@ -79,6 +83,8 @@ public final class NetworkStackConstants {
public static final int IPV4_SRC_ADDR_OFFSET = 12;
public static final int IPV4_DST_ADDR_OFFSET = 16;
public static final int IPV4_ADDR_LEN = 4;
+ public static final Inet4Address IPV4_ADDR_ALL = intToInet4AddressHTH(0xffffffff);
+ public static final Inet4Address IPV4_ADDR_ANY = intToInet4AddressHTH(0x0);
/**
* IPv6 constants.
diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java
index 51d50d9eb13a..4abd77e9cfde 100644
--- a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java
+++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpLeaseRepositoryTest.java
@@ -21,6 +21,8 @@ import static android.net.dhcp.DhcpLease.HOSTNAME_NONE;
import static android.net.dhcp.DhcpLeaseRepository.CLIENTID_UNSPEC;
import static android.net.dhcp.DhcpLeaseRepository.INETADDR_UNSPEC;
+import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -55,7 +57,6 @@ import java.util.Set;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class DhcpLeaseRepositoryTest {
- private static final Inet4Address INET4_ANY = (Inet4Address) Inet4Address.ANY;
private static final Inet4Address TEST_DEF_ROUTER = parseAddr4("192.168.42.247");
private static final Inet4Address TEST_SERVER_ADDR = parseAddr4("192.168.42.241");
private static final Inet4Address TEST_RESERVED_ADDR = parseAddr4("192.168.42.243");
@@ -108,7 +109,7 @@ public class DhcpLeaseRepositoryTest {
MacAddress newMac = MacAddress.fromBytes(hwAddrBytes);
final String hostname = "host_" + i;
final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, newMac,
- INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, hostname);
+ IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, hostname);
assertNotNull(lease);
assertEquals(newMac, lease.getHwAddr());
@@ -130,7 +131,7 @@ public class DhcpLeaseRepositoryTest {
try {
mRepo.getOffer(null, TEST_MAC_2,
- INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+ IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
fail("Should be out of addresses");
} catch (DhcpLeaseRepository.OutOfAddressesException e) {
// Expected
@@ -181,11 +182,11 @@ public class DhcpLeaseRepositoryTest {
public void testGetOffer_StableAddress() throws Exception {
for (final MacAddress macAddr : new MacAddress[] { TEST_MAC_1, TEST_MAC_2, TEST_MAC_3 }) {
final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, macAddr,
- INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+ IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
// Same lease is offered twice
final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, macAddr,
- INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+ IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
assertEquals(lease, newLease);
}
}
@@ -196,7 +197,7 @@ public class DhcpLeaseRepositoryTest {
mRepo.updateParams(newPrefix, TEST_EXCL_SET, TEST_LEASE_TIME_MS);
DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
- INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+ IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
assertTrue(newPrefix.contains(lease.getNetAddr()));
}
@@ -205,7 +206,7 @@ public class DhcpLeaseRepositoryTest {
requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1, TEST_HOSTNAME_1);
DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
- INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+ IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
assertEquals(TEST_INETADDR_1, offer.getNetAddr());
assertEquals(TEST_HOSTNAME_1, offer.getHostname());
}
@@ -213,12 +214,13 @@ public class DhcpLeaseRepositoryTest {
@Test
public void testGetOffer_ClientIdHasExistingLease() throws Exception {
final byte[] clientId = new byte[] { 1, 2 };
- mRepo.requestLease(clientId, TEST_MAC_1, INET4_ANY /* clientAddr */,
- INET4_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false, TEST_HOSTNAME_1);
+ mRepo.requestLease(clientId, TEST_MAC_1, IPV4_ADDR_ANY /* clientAddr */,
+ IPV4_ADDR_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false,
+ TEST_HOSTNAME_1);
// Different MAC, but same clientId
DhcpLease offer = mRepo.getOffer(clientId, TEST_MAC_2,
- INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+ IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
assertEquals(TEST_INETADDR_1, offer.getNetAddr());
assertEquals(TEST_HOSTNAME_1, offer.getHostname());
}
@@ -227,12 +229,13 @@ public class DhcpLeaseRepositoryTest {
public void testGetOffer_DifferentClientId() throws Exception {
final byte[] clientId1 = new byte[] { 1, 2 };
final byte[] clientId2 = new byte[] { 3, 4 };
- mRepo.requestLease(clientId1, TEST_MAC_1, INET4_ANY /* clientAddr */,
- INET4_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false, TEST_HOSTNAME_1);
+ mRepo.requestLease(clientId1, TEST_MAC_1, IPV4_ADDR_ANY /* clientAddr */,
+ IPV4_ADDR_ANY /* relayAddr */, TEST_INETADDR_1 /* reqAddr */, false,
+ TEST_HOSTNAME_1);
// Same MAC, different client ID
DhcpLease offer = mRepo.getOffer(clientId2, TEST_MAC_1,
- INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+ IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
// Obtains a different address
assertNotEquals(TEST_INETADDR_1, offer.getNetAddr());
assertEquals(HOSTNAME_NONE, offer.getHostname());
@@ -241,7 +244,7 @@ public class DhcpLeaseRepositoryTest {
@Test
public void testGetOffer_RequestedAddress() throws Exception {
- DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */,
+ DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */,
TEST_INETADDR_1 /* reqAddr */, TEST_HOSTNAME_1);
assertEquals(TEST_INETADDR_1, offer.getNetAddr());
assertEquals(TEST_HOSTNAME_1, offer.getHostname());
@@ -250,14 +253,14 @@ public class DhcpLeaseRepositoryTest {
@Test
public void testGetOffer_RequestedAddressInUse() throws Exception {
requestLeaseSelecting(TEST_MAC_1, TEST_INETADDR_1);
- DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2, INET4_ANY /* relayAddr */,
+ DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2, IPV4_ADDR_ANY /* relayAddr */,
TEST_INETADDR_1 /* reqAddr */, HOSTNAME_NONE);
assertNotEquals(TEST_INETADDR_1, offer.getNetAddr());
}
@Test
public void testGetOffer_RequestedAddressReserved() throws Exception {
- DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */,
+ DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */,
TEST_RESERVED_ADDR /* reqAddr */, HOSTNAME_NONE);
assertNotEquals(TEST_RESERVED_ADDR, offer.getNetAddr());
}
@@ -265,7 +268,7 @@ public class DhcpLeaseRepositoryTest {
@Test
public void testGetOffer_RequestedAddressInvalid() throws Exception {
final Inet4Address invalidAddr = parseAddr4("192.168.42.0");
- DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */,
+ DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */,
invalidAddr /* reqAddr */, HOSTNAME_NONE);
assertNotEquals(invalidAddr, offer.getNetAddr());
}
@@ -273,7 +276,7 @@ public class DhcpLeaseRepositoryTest {
@Test
public void testGetOffer_RequestedAddressOutsideSubnet() throws Exception {
final Inet4Address invalidAddr = parseAddr4("192.168.254.2");
- DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* relayAddr */,
+ DhcpLease offer = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* relayAddr */,
invalidAddr /* reqAddr */, HOSTNAME_NONE);
assertNotEquals(invalidAddr, offer.getNetAddr());
}
@@ -322,7 +325,7 @@ public class DhcpLeaseRepositoryTest {
@Test(expected = DhcpLeaseRepository.InvalidSubnetException.class)
public void testRequestLease_SelectingRelayInInvalidSubnet() throws Exception {
- mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, INET4_ANY /* clientAddr */,
+ mRepo.requestLease(CLIENTID_UNSPEC, TEST_MAC_1, IPV4_ADDR_ANY /* clientAddr */,
parseAddr4("192.168.128.1") /* relayAddr */, TEST_INETADDR_1 /* reqAddr */,
true /* sidSet */, HOSTNAME_NONE);
}
@@ -419,14 +422,14 @@ public class DhcpLeaseRepositoryTest {
public void testReleaseLease_StableOffer() throws Exception {
for (MacAddress mac : new MacAddress[] { TEST_MAC_1, TEST_MAC_2, TEST_MAC_3 }) {
final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, mac,
- INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+ IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
requestLeaseSelecting(mac, lease.getNetAddr());
mRepo.releaseLease(CLIENTID_UNSPEC, mac, lease.getNetAddr());
// Same lease is offered after it was released
final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, mac,
- INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+ IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
assertEquals(lease.getNetAddr(), newLease.getNetAddr());
}
}
@@ -434,13 +437,13 @@ public class DhcpLeaseRepositoryTest {
@Test
public void testMarkLeaseDeclined() throws Exception {
final DhcpLease lease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
- INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+ IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
mRepo.markLeaseDeclined(lease.getNetAddr());
// Same lease is not offered again
final DhcpLease newLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
- INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
+ IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
assertNotEquals(lease.getNetAddr(), newLease.getNetAddr());
}
@@ -457,16 +460,16 @@ public class DhcpLeaseRepositoryTest {
// Last 2 addresses: addresses marked declined should be used
final DhcpLease firstLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_1,
- INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_1);
+ IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_1);
requestLeaseSelecting(TEST_MAC_1, firstLease.getNetAddr());
final DhcpLease secondLease = mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_2,
- INET4_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_2);
+ IPV4_ADDR_ANY /* relayAddr */, INETADDR_UNSPEC /* reqAddr */, TEST_HOSTNAME_2);
requestLeaseSelecting(TEST_MAC_2, secondLease.getNetAddr());
// Now out of addresses
try {
- mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_3, INET4_ANY /* relayAddr */,
+ mRepo.getOffer(CLIENTID_UNSPEC, TEST_MAC_3, IPV4_ADDR_ANY /* relayAddr */,
INETADDR_UNSPEC /* reqAddr */, HOSTNAME_NONE);
fail("Repository should be out of addresses and throw");
} catch (DhcpLeaseRepository.OutOfAddressesException e) { /* expected */ }
@@ -480,7 +483,8 @@ public class DhcpLeaseRepositoryTest {
private DhcpLease requestLease(@NonNull MacAddress macAddr, @NonNull Inet4Address clientAddr,
@Nullable Inet4Address reqAddr, @Nullable String hostname, boolean sidSet)
throws DhcpLeaseRepository.DhcpLeaseException {
- return mRepo.requestLease(CLIENTID_UNSPEC, macAddr, clientAddr, INET4_ANY /* relayAddr */,
+ return mRepo.requestLease(CLIENTID_UNSPEC, macAddr, clientAddr,
+ IPV4_ADDR_ANY /* relayAddr */,
reqAddr, sidSet, hostname);
}
@@ -490,7 +494,7 @@ public class DhcpLeaseRepositoryTest {
private DhcpLease requestLeaseSelecting(@NonNull MacAddress macAddr,
@NonNull Inet4Address reqAddr, @Nullable String hostname)
throws DhcpLeaseRepository.DhcpLeaseException {
- return requestLease(macAddr, INET4_ANY /* clientAddr */, reqAddr, hostname,
+ return requestLease(macAddr, IPV4_ADDR_ANY /* clientAddr */, reqAddr, hostname,
true /* sidSet */);
}
@@ -507,7 +511,7 @@ public class DhcpLeaseRepositoryTest {
*/
private DhcpLease requestLeaseInitReboot(@NonNull MacAddress macAddr,
@NonNull Inet4Address reqAddr) throws DhcpLeaseRepository.DhcpLeaseException {
- return requestLease(macAddr, INET4_ANY /* clientAddr */, reqAddr, HOSTNAME_NONE,
+ return requestLease(macAddr, IPV4_ADDR_ANY /* clientAddr */, reqAddr, HOSTNAME_NONE,
false /* sidSet */);
}
diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java
index a592809618e6..7544e72da02e 100644
--- a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java
+++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java
@@ -16,9 +16,27 @@
package android.net.dhcp;
-import static android.net.NetworkUtils.getBroadcastAddress;
-import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
-import static android.net.dhcp.DhcpPacket.*;
+import static android.net.dhcp.DhcpPacket.DHCP_BROADCAST_ADDRESS;
+import static android.net.dhcp.DhcpPacket.DHCP_DNS_SERVER;
+import static android.net.dhcp.DhcpPacket.DHCP_DOMAIN_NAME;
+import static android.net.dhcp.DhcpPacket.DHCP_LEASE_TIME;
+import static android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_ACK;
+import static android.net.dhcp.DhcpPacket.DHCP_MESSAGE_TYPE_OFFER;
+import static android.net.dhcp.DhcpPacket.DHCP_MTU;
+import static android.net.dhcp.DhcpPacket.DHCP_REBINDING_TIME;
+import static android.net.dhcp.DhcpPacket.DHCP_RENEWAL_TIME;
+import static android.net.dhcp.DhcpPacket.DHCP_ROUTER;
+import static android.net.dhcp.DhcpPacket.DHCP_SUBNET_MASK;
+import static android.net.dhcp.DhcpPacket.DHCP_VENDOR_INFO;
+import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP;
+import static android.net.dhcp.DhcpPacket.ENCAP_L2;
+import static android.net.dhcp.DhcpPacket.ENCAP_L3;
+import static android.net.dhcp.DhcpPacket.INADDR_ANY;
+import static android.net.dhcp.DhcpPacket.INFINITE_LEASE;
+import static android.net.dhcp.DhcpPacket.ParseException;
+import static android.net.shared.Inet4AddressUtils.getBroadcastAddress;
+import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -30,11 +48,15 @@ import android.net.DhcpResults;
import android.net.LinkAddress;
import android.net.NetworkUtils;
import android.net.metrics.DhcpErrorEvent;
-import android.support.test.runner.AndroidJUnit4;
import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import com.android.internal.util.HexDump;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.io.ByteArrayOutputStream;
import java.net.Inet4Address;
import java.nio.ByteBuffer;
@@ -44,10 +66,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Random;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public class DhcpPacketTest {
@@ -60,9 +78,9 @@ public class DhcpPacketTest {
SERVER_ADDR, PREFIX_LENGTH);
private static final String HOSTNAME = "testhostname";
private static final short MTU = 1500;
- // Use our own empty address instead of Inet4Address.ANY or INADDR_ANY to ensure that the code
+ // Use our own empty address instead of IPV4_ADDR_ANY or INADDR_ANY to ensure that the code
// doesn't use == instead of equals when comparing addresses.
- private static final Inet4Address ANY = (Inet4Address) v4Address("0.0.0.0");
+ private static final Inet4Address ANY = v4Address("0.0.0.0");
private static final byte[] CLIENT_MAC = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java
index 3ca0564f24d6..1004382b3adf 100644
--- a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java
+++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServingParamsTest.java
@@ -17,8 +17,8 @@
package android.net.dhcp;
import static android.net.InetAddresses.parseNumericAddress;
-import static android.net.NetworkUtils.inet4AddressToIntHTH;
import static android.net.dhcp.DhcpServingParams.MTU_UNSET;
+import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -27,8 +27,8 @@ import static junit.framework.Assert.assertTrue;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.LinkAddress;
-import android.net.NetworkUtils;
import android.net.dhcp.DhcpServingParams.InvalidParameterException;
+import android.net.shared.Inet4AddressUtils;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -200,7 +200,7 @@ public class DhcpServingParamsTest {
}
private static int[] toIntArray(Collection<Inet4Address> addrs) {
- return addrs.stream().mapToInt(NetworkUtils::inet4AddressToIntHTH).toArray();
+ return addrs.stream().mapToInt(Inet4AddressUtils::inet4AddressToIntHTH).toArray();
}
private static <T> void assertContains(@NonNull Set<T> set, @NonNull Set<T> subset) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 4f6a4ad94479..a1aefabfc7f2 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1714,6 +1714,12 @@ class SettingsProtoDumpUtil {
dumpSetting(s, p,
Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
SecureSettingsProto.Accessibility.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
+ dumpSetting(s, p,
+ Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
+ SecureSettingsProto.Accessibility.NON_INTERACTIVE_UI_TIMEOUT_MS);
+ dumpSetting(s, p,
+ Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS,
+ SecureSettingsProto.Accessibility.INTERACTIVE_UI_TIMEOUT_MS);
p.end(accessibilityToken);
dumpSetting(s, p,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 904478efb568..015085205460 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -111,6 +111,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
private static final int MSG_SHOW_CHARGING_ANIMATION = 44 << MSG_SHIFT;
private static final int MSG_SHOW_PINNING_TOAST_ENTER_EXIT = 45 << MSG_SHIFT;
private static final int MSG_SHOW_PINNING_TOAST_ESCAPE = 46 << MSG_SHIFT;
+ private static final int MSG_DISPLAY_READY = 47 << MSG_SHIFT;
public static final int FLAG_EXCLUDE_NONE = 0;
public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -274,6 +275,11 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
default void onBiometricHelp(String message) { }
default void onBiometricError(String error) { }
default void hideBiometricDialog() { }
+
+ /**
+ * @see IStatusBar#onDisplayReady(int)
+ */
+ default void onDisplayReady(int displayId) { }
}
@VisibleForTesting
@@ -761,6 +767,13 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
}
}
+ @Override
+ public void onDisplayReady(int displayId) {
+ synchronized (mLock) {
+ mHandler.obtainMessage(MSG_DISPLAY_READY, displayId, 0).sendToTarget();
+ }
+ }
+
private final class H extends Handler {
private H(Looper l) {
super(l);
@@ -1015,6 +1028,11 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
mCallbacks.get(i).showPinningEscapeToast();
}
break;
+ case MSG_DISPLAY_READY:
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).onDisplayReady(msg.arg1);
+ }
+ break;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
index 9740d1dd6d1c..e11ec2d24e29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.systemui.Dependency.MAIN_HANDLER_NAME;
+import static com.android.systemui.SysUiServiceProvider.getComponent;
import android.content.Context;
import android.hardware.display.DisplayManager;
@@ -34,6 +35,7 @@ import android.view.WindowManagerGlobal;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.DarkIconDispatcher;
+import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
import com.android.systemui.statusbar.phone.LightBarController;
@@ -48,7 +50,7 @@ import javax.inject.Singleton;
/** A controller to handle navigation bars. */
@Singleton
-public class NavigationBarController implements DisplayListener {
+public class NavigationBarController implements DisplayListener, Callbacks {
private static final String TAG = NavigationBarController.class.getName();
@@ -65,13 +67,11 @@ public class NavigationBarController implements DisplayListener {
mHandler = handler;
mDisplayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
mDisplayManager.registerDisplayListener(this, mHandler);
+ getComponent(mContext, CommandQueue.class).addCallback(this);
}
@Override
- public void onDisplayAdded(int displayId) {
- Display display = mDisplayManager.getDisplay(displayId);
- createNavigationBar(display);
- }
+ public void onDisplayAdded(int displayId) { }
@Override
public void onDisplayRemoved(int displayId) {
@@ -79,7 +79,12 @@ public class NavigationBarController implements DisplayListener {
}
@Override
- public void onDisplayChanged(int displayId) {
+ public void onDisplayChanged(int displayId) { }
+
+ @Override
+ public void onDisplayReady(int displayId) {
+ Display display = mDisplayManager.getDisplay(displayId);
+ createNavigationBar(display);
}
// TODO(b/117478341): I use {@code includeDefaultDisplay} to make this method compatible to
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java
index 73f3b43aad62..6177344a3ef4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java
@@ -51,6 +51,7 @@ public class NavigationBarButtonTest extends SysuiTestCase {
@Before
public void setup() {
+ mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
final Display display = createVirtualDisplay();
final SysuiTestableContext context =
(SysuiTestableContext) mContext.createDisplayContext(display);
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 8adc416fda95..84577f125f1d 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -16,6 +16,9 @@
package com.android.server;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.Context;
import android.os.Environment;
@@ -46,6 +49,7 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.annotation.Retention;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
@@ -55,7 +59,8 @@ import java.util.Set;
/**
* Monitors the health of packages on the system and notifies interested observers when packages
- * fail. All registered observers will be notified until an observer takes a mitigation action.
+ * fail. On failure, the registered observer with the least user impacting mitigation will
+ * be notified.
*/
public class PackageWatchdog {
private static final String TAG = "PackageWatchdog";
@@ -78,7 +83,8 @@ public class PackageWatchdog {
private final Context mContext;
// Handler to run package cleanup runnables
private final Handler mTimerHandler;
- private final Handler mIoHandler;
+ // Handler for processing IO and observer actions
+ private final Handler mWorkerHandler;
// Contains (observer-name -> observer-handle) that have ever been registered from
// previous boots. Observers with all packages expired are periodically pruned.
// It is saved to disk on system shutdown and repouplated on startup so it survives reboots.
@@ -101,7 +107,7 @@ public class PackageWatchdog {
mPolicyFile = new AtomicFile(new File(new File(Environment.getDataDirectory(), "system"),
"package-watchdog.xml"));
mTimerHandler = new Handler(Looper.myLooper());
- mIoHandler = BackgroundThread.getHandler();
+ mWorkerHandler = BackgroundThread.getHandler();
mPackageCleanup = this::rescheduleCleanup;
loadFromFile();
}
@@ -115,7 +121,7 @@ public class PackageWatchdog {
mContext = context;
mPolicyFile = new AtomicFile(new File(context.getFilesDir(), "package-watchdog.xml"));
mTimerHandler = new Handler(looper);
- mIoHandler = mTimerHandler;
+ mWorkerHandler = mTimerHandler;
mPackageCleanup = this::rescheduleCleanup;
loadFromFile();
}
@@ -228,49 +234,46 @@ public class PackageWatchdog {
/**
* Called when a process fails either due to a crash or ANR.
*
- * <p>All registered observers for the packages contained in the process will be notified in
- * order of priority until an observer signifies that it has taken action and other observers
- * should not notified.
+ * <p>For each package contained in the process, one registered observer with the least user
+ * impact will be notified for mitigation.
*
* <p>This method could be called frequently if there is a severe problem on the device.
*/
public void onPackageFailure(String[] packages) {
- ArrayMap<String, List<PackageHealthObserver>> packagesToReport = new ArrayMap<>();
- synchronized (mLock) {
- if (mAllObservers.isEmpty()) {
- return;
- }
+ mWorkerHandler.post(() -> {
+ synchronized (mLock) {
+ if (mAllObservers.isEmpty()) {
+ return;
+ }
- for (int pIndex = 0; pIndex < packages.length; pIndex++) {
- // Observers interested in receiving packageName failures
- List<PackageHealthObserver> observersToNotify = new ArrayList<>();
- for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
- PackageHealthObserver registeredObserver =
- mAllObservers.valueAt(oIndex).mRegisteredObserver;
- if (registeredObserver != null) {
- observersToNotify.add(registeredObserver);
+ for (int pIndex = 0; pIndex < packages.length; pIndex++) {
+ String packageToReport = packages[pIndex];
+ // Observer that will receive failure for packageToReport
+ PackageHealthObserver currentObserverToNotify = null;
+ int currentObserverImpact = Integer.MAX_VALUE;
+
+ // Find observer with least user impact
+ for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
+ ObserverInternal observer = mAllObservers.valueAt(oIndex);
+ PackageHealthObserver registeredObserver = observer.mRegisteredObserver;
+ if (registeredObserver != null
+ && observer.onPackageFailure(packageToReport)) {
+ int impact = registeredObserver.onHealthCheckFailed(packageToReport);
+ if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
+ && impact < currentObserverImpact) {
+ currentObserverToNotify = registeredObserver;
+ currentObserverImpact = impact;
+ }
+ }
}
- }
- // Save interested observers and notify them outside the lock
- if (!observersToNotify.isEmpty()) {
- packagesToReport.put(packages[pIndex], observersToNotify);
- }
- }
- }
- // Notify observers
- for (int pIndex = 0; pIndex < packagesToReport.size(); pIndex++) {
- List<PackageHealthObserver> observers = packagesToReport.valueAt(pIndex);
- String packageName = packages[pIndex];
- for (int oIndex = 0; oIndex < observers.size(); oIndex++) {
- PackageHealthObserver observer = observers.get(oIndex);
- if (mAllObservers.get(observer.getName()).onPackageFailure(packageName)
- && observer.onHealthCheckFailed(packageName)) {
- // Observer has handled, do not notify others
- break;
+ // Execute action with least user impact
+ if (currentObserverToNotify != null) {
+ currentObserverToNotify.execute(packageToReport);
+ }
}
}
- }
+ });
}
// TODO(zezeozue): Optimize write? Maybe only write a separate smaller file?
@@ -278,21 +281,46 @@ public class PackageWatchdog {
/** Writes the package information to file during shutdown. */
public void writeNow() {
if (!mAllObservers.isEmpty()) {
- mIoHandler.removeCallbacks(this::saveToFile);
+ mWorkerHandler.removeCallbacks(this::saveToFile);
pruneObservers(SystemClock.uptimeMillis() - mUptimeAtLastRescheduleMs);
saveToFile();
Slog.i(TAG, "Last write to update package durations");
}
}
+ /** Possible severity values of the user impact of a {@link PackageHealthObserver#execute}. */
+ @Retention(SOURCE)
+ @IntDef(value = {PackageHealthObserverImpact.USER_IMPACT_NONE,
+ PackageHealthObserverImpact.USER_IMPACT_LOW,
+ PackageHealthObserverImpact.USER_IMPACT_MEDIUM,
+ PackageHealthObserverImpact.USER_IMPACT_HIGH})
+ public @interface PackageHealthObserverImpact {
+ /** No action to take. */
+ int USER_IMPACT_NONE = 0;
+ /* Action has low user impact, user of a device will barely notice. */
+ int USER_IMPACT_LOW = 1;
+ /* Action has medium user impact, user of a device will likely notice. */
+ int USER_IMPACT_MEDIUM = 3;
+ /* Action has high user impact, a last resort, user of a device will be very frustrated. */
+ int USER_IMPACT_HIGH = 5;
+ }
+
/** Register instances of this interface to receive notifications on package failure. */
public interface PackageHealthObserver {
/**
* Called when health check fails for the {@code packageName}.
- * @return {@code true} if action was taken and other observers should not be notified of
- * this failure, {@code false} otherwise.
+ *
+ * @return any one of {@link PackageHealthObserverImpact} to express the impact
+ * to the user on {@link #execute}
*/
- boolean onHealthCheckFailed(String packageName);
+ @PackageHealthObserverImpact int onHealthCheckFailed(String packageName);
+
+ /**
+ * Executes mitigation for {@link #onHealthCheckFailed}.
+ *
+ * @return {@code true} if action was executed successfully, {@code false} otherwise
+ */
+ boolean execute(String packageName);
// TODO(zezeozue): Ensure uniqueness?
/**
@@ -442,8 +470,8 @@ public class PackageWatchdog {
}
private void saveToFileAsync() {
- mIoHandler.removeCallbacks(this::saveToFile);
- mIoHandler.post(this::saveToFile);
+ mWorkerHandler.removeCallbacks(this::saveToFile);
+ mWorkerHandler.post(this::saveToFile);
}
/**
@@ -606,7 +634,11 @@ public class PackageWatchdog {
} else {
mFailures++;
}
- return mFailures >= TRIGGER_FAILURE_COUNT;
+ boolean failed = mFailures >= TRIGGER_FAILURE_COUNT;
+ if (failed) {
+ mFailures = 0;
+ }
+ return failed;
}
}
}
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index d09823efb6fa..a5a515f93e75 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -34,11 +34,11 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.Preconditions;
@@ -48,6 +48,9 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
/**
* Find the best Service, and bind to it.
@@ -61,16 +64,20 @@ public class ServiceWatcher implements ServiceConnection {
public static final String EXTRA_SERVICE_VERSION = "serviceVersion";
public static final String EXTRA_SERVICE_IS_MULTIUSER = "serviceIsMultiuser";
+
+ /** Function to run on binder interface. */
+ public interface BinderRunner {
+ /** Called to run client code with the binder. */
+ void run(IBinder binder) throws RemoteException;
+ }
+
/**
- * The runner that runs on the binder retrieved from {@link ServiceWatcher}.
+ * Function to run on binder interface.
+ * @param <T> Type to return.
*/
- public interface BinderRunner {
- /**
- * Runs on the retrieved binder.
- *
- * @param binder the binder retrieved from the {@link ServiceWatcher}.
- */
- void run(IBinder binder);
+ public interface BlockingBinderRunner<T> {
+ /** Called to run client code with the binder. */
+ T run(IBinder binder) throws RemoteException;
}
public static ArrayList<HashSet<Signature>> getSignatureSets(Context context,
@@ -120,18 +127,14 @@ public class ServiceWatcher implements ServiceConnection {
private final Handler mHandler;
- // this lock is held to ensure the service binder is not exposed (via runOnBinder) until after
- // the new service initialization work has completed
- private final Object mBindLock = new Object();
-
// read/write from handler thread
+ private IBinder mBestService;
private int mCurrentUserId;
// read from any thread, write from handler thread
private volatile ComponentName mBestComponent;
private volatile int mBestVersion;
private volatile int mBestUserId;
- private volatile IBinder mBestService;
public ServiceWatcher(Context context, String logTag, String action,
int overlaySwitchResId, int defaultServicePackageNameResId,
@@ -163,17 +166,9 @@ public class ServiceWatcher implements ServiceConnection {
mBestService = null;
}
- // called on handler thread
- @GuardedBy("mBindLock")
- protected void onBind() {
- Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
- }
+ protected void onBind() {}
- // called on handler thread
- @GuardedBy("mBindLock")
- protected void onUnbind() {
- Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
- }
+ protected void onUnbind() {}
/**
* Start this watcher, including binding to the current best match and
@@ -248,25 +243,6 @@ public class ServiceWatcher implements ServiceConnection {
return bestComponent == null ? null : bestComponent.getPackageName();
}
- /**
- * Runs the given BinderRunner if currently connected. All invocations to runOnBinder are run
- * serially.
- */
- public final void runOnBinder(BinderRunner runner) {
- synchronized (mBindLock) {
- IBinder service = mBestService;
- if (service != null) {
- try {
- runner.run(service);
- } catch (Exception e) {
- // remote exceptions cannot be allowed to crash system server
- Log.e(TAG, "exception while while running " + runner + " on " + service
- + " from " + this, e);
- }
- }
- }
- }
-
private boolean isServiceMissing() {
return mContext.getPackageManager().queryIntentServicesAsUser(new Intent(mAction),
PackageManager.MATCH_DIRECT_BOOT_AWARE
@@ -380,28 +356,66 @@ public class ServiceWatcher implements ServiceConnection {
mBestUserId = UserHandle.USER_NULL;
}
+ /**
+ * Runs the given function asynchronously if currently connected. Suppresses any RemoteException
+ * thrown during execution.
+ */
+ public final void runOnBinder(BinderRunner runner) {
+ runOnHandler(() -> {
+ if (mBestService == null) {
+ return;
+ }
+
+ try {
+ runner.run(mBestService);
+ } catch (RuntimeException e) {
+ // the code being run is privileged, but may be outside the system server, and thus
+ // we cannot allow runtime exceptions to crash the system server
+ Log.e(TAG, "exception while while running " + runner + " on " + mBestService
+ + " from " + this, e);
+ } catch (RemoteException e) {
+ // do nothing
+ }
+ });
+ }
+
+ /**
+ * Runs the given function synchronously if currently connected, and returns the default value
+ * if not currently connected or if any exception is thrown.
+ */
+ public final <T> T runOnBinderBlocking(BlockingBinderRunner<T> runner, T defaultValue) {
+ try {
+ return runOnHandlerBlocking(() -> {
+ if (mBestService == null) {
+ return defaultValue;
+ }
+
+ try {
+ return runner.run(mBestService);
+ } catch (RemoteException e) {
+ return defaultValue;
+ }
+ });
+ } catch (InterruptedException e) {
+ return defaultValue;
+ }
+ }
+
@Override
public final void onServiceConnected(ComponentName component, IBinder binder) {
- mHandler.post(() -> {
+ runOnHandler(() -> {
if (D) Log.d(mTag, component + " connected");
-
- // hold the lock so that mBestService cannot be used by runOnBinder until complete
- synchronized (mBindLock) {
- mBestService = binder;
- onBind();
- }
+ mBestService = binder;
+ onBind();
});
}
@Override
public final void onServiceDisconnected(ComponentName component) {
- mHandler.post(() -> {
+ runOnHandler(() -> {
if (D) Log.d(mTag, component + " disconnected");
-
mBestService = null;
- synchronized (mBindLock) {
- onUnbind();
- }
+ onUnbind();
});
}
@@ -410,4 +424,32 @@ public class ServiceWatcher implements ServiceConnection {
ComponentName bestComponent = mBestComponent;
return bestComponent == null ? "null" : bestComponent.toShortString() + "@" + mBestVersion;
}
+
+ private void runOnHandler(Runnable r) {
+ if (Looper.myLooper() == mHandler.getLooper()) {
+ r.run();
+ } else {
+ mHandler.post(r);
+ }
+ }
+
+ private <T> T runOnHandlerBlocking(Callable<T> c) throws InterruptedException {
+ if (Looper.myLooper() == mHandler.getLooper()) {
+ try {
+ return c.call();
+ } catch (Exception e) {
+ // Function cannot throw exception, this should never happen
+ throw new IllegalStateException(e);
+ }
+ } else {
+ FutureTask<T> task = new FutureTask<>(c);
+ mHandler.post(task);
+ try {
+ return task.get();
+ } catch (ExecutionException e) {
+ // Function cannot throw exception, this should never happen
+ throw new IllegalStateException(e);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index ea6d435c7ba5..f6e698ff7839 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -33,8 +33,10 @@ import android.media.AudioAttributes;
import android.media.AudioManager;
import android.os.BatteryStats;
import android.os.Binder;
+import android.os.ExternalVibration;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IExternalVibratorService;
import android.os.IVibratorService;
import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
@@ -75,16 +77,18 @@ public class VibratorService extends IVibratorService.Stub
private static final String TAG = "VibratorService";
private static final boolean DEBUG = false;
private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
+ private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service";
private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 };
- // Scale levels. Each level is defined as the delta between the current setting and the default
- // intensity for that type of vibration (i.e. current - default).
- private static final int SCALE_VERY_LOW = -2;
- private static final int SCALE_LOW = -1;
- private static final int SCALE_NONE = 0;
- private static final int SCALE_HIGH = 1;
- private static final int SCALE_VERY_HIGH = 2;
+ // Scale levels. Each level, except MUTE, is defined as the delta between the current setting
+ // and the default intensity for that type of vibration (i.e. current - default).
+ private static final int SCALE_MUTE = IExternalVibratorService.SCALE_MUTE; // -100
+ private static final int SCALE_VERY_LOW = IExternalVibratorService.SCALE_VERY_LOW; // -2
+ private static final int SCALE_LOW = IExternalVibratorService.SCALE_LOW; // -1
+ private static final int SCALE_NONE = IExternalVibratorService.SCALE_NONE; // 0
+ private static final int SCALE_HIGH = IExternalVibratorService.SCALE_HIGH; // 1
+ private static final int SCALE_VERY_HIGH = IExternalVibratorService.SCALE_VERY_HIGH; // 2
// Gamma adjustments for scale levels.
private static final float SCALE_VERY_LOW_GAMMA = 2.0f;
@@ -111,6 +115,7 @@ public class VibratorService extends IVibratorService.Stub
private final int mPreviousVibrationsLimit;
private final boolean mAllowPriorityVibrationsInLowPowerMode;
private final boolean mSupportsAmplitudeControl;
+ private final boolean mSupportsExternalControl;
private final int mDefaultVibrationAmplitude;
private final SparseArray<VibrationEffect> mFallbackEffects;
private final SparseArray<Integer> mProcStatesCache = new SparseArray();
@@ -138,18 +143,20 @@ public class VibratorService extends IVibratorService.Stub
@GuardedBy("mLock")
private Vibration mCurrentVibration;
private int mCurVibUid = -1;
+ private ExternalVibration mCurrentExternalVibration;
+ private boolean mVibratorUnderExternalControl;
private boolean mLowPowerMode;
private int mHapticFeedbackIntensity;
private int mNotificationIntensity;
private int mRingIntensity;
- native static boolean vibratorExists();
- native static void vibratorInit();
- native static void vibratorOn(long milliseconds);
- native static void vibratorOff();
- native static boolean vibratorSupportsAmplitudeControl();
- native static void vibratorSetAmplitude(int amplitude);
- native static long vibratorPerformEffect(long effect, long strength);
+ static native boolean vibratorExists();
+ static native void vibratorInit();
+ static native void vibratorOn(long milliseconds);
+ static native void vibratorOff();
+ static native boolean vibratorSupportsAmplitudeControl();
+ static native void vibratorSetAmplitude(int amplitude);
+ static native long vibratorPerformEffect(long effect, long strength);
static native boolean vibratorSupportsExternalControl();
static native void vibratorSetExternalControl(boolean enabled);
@@ -218,6 +225,9 @@ public class VibratorService extends IVibratorService.Stub
}
public boolean isHapticFeedback() {
+ if (VibratorService.this.isHapticFeedback(usageHint)) {
+ return true;
+ }
if (effect instanceof VibrationEffect.Prebaked) {
VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
switch (prebaked.getId()) {
@@ -239,19 +249,11 @@ public class VibratorService extends IVibratorService.Stub
}
public boolean isNotification() {
- switch (usageHint) {
- case AudioAttributes.USAGE_NOTIFICATION:
- case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
- case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
- case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
- return true;
- default:
- return false;
- }
+ return VibratorService.this.isNotification(usageHint);
}
public boolean isRingtone() {
- return usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
+ return VibratorService.this.isRingtone(usageHint);
}
public boolean isFromSystem() {
@@ -332,6 +334,7 @@ public class VibratorService extends IVibratorService.Stub
vibratorOff();
mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
+ mSupportsExternalControl = vibratorSupportsExternalControl();
mContext = context;
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
@@ -379,6 +382,8 @@ public class VibratorService extends IVibratorService.Stub
mScaleLevels.put(SCALE_NONE, new ScaleLevel(SCALE_NONE_GAMMA));
mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_HIGH_GAMMA));
mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_VERY_HIGH_GAMMA));
+
+ ServiceManager.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
}
private VibrationEffect createEffectFromResource(int resId) {
@@ -562,6 +567,16 @@ public class VibratorService extends IVibratorService.Stub
}
}
+
+ // If something has external control of the vibrator, assume that it's more
+ // important for now.
+ if (mCurrentExternalVibration != null) {
+ if (DEBUG) {
+ Slog.d(TAG, "Ignoring incoming vibration for current external vibration");
+ }
+ return;
+ }
+
// If the current vibration is repeating and the incoming one is non-repeating,
// then ignore the non-repeating vibration. This is so that we don't cancel
// vibrations that are meant to grab the attention of the user, like ringtones and
@@ -648,6 +663,11 @@ public class VibratorService extends IVibratorService.Stub
mThread.cancel();
mThread = null;
}
+ if (mCurrentExternalVibration != null) {
+ mCurrentExternalVibration.mute();
+ mCurrentExternalVibration = null;
+ setVibratorUnderExternalControl(false);
+ }
doVibratorOff();
reportFinishVibrationLocked();
} finally {
@@ -1095,6 +1115,26 @@ public class VibratorService extends IVibratorService.Stub
}
}
+ private static boolean isNotification(int usageHint) {
+ switch (usageHint) {
+ case AudioAttributes.USAGE_NOTIFICATION:
+ case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
+ case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
+ case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private static boolean isRingtone(int usageHint) {
+ return usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
+ }
+
+ private static boolean isHapticFeedback(int usageHint) {
+ return usageHint == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION;
+ }
+
private void noteVibratorOnLocked(int uid, long millis) {
try {
mBatteryStatsService.noteVibratorOn(uid, millis);
@@ -1116,6 +1156,18 @@ public class VibratorService extends IVibratorService.Stub
}
}
+ private void setVibratorUnderExternalControl(boolean externalControl) {
+ if (DEBUG) {
+ if (externalControl) {
+ Slog.d(TAG, "Vibrator going under external control.");
+ } else {
+ Slog.d(TAG, "Taking back control of vibrator.");
+ }
+ }
+ mVibratorUnderExternalControl = externalControl;
+ vibratorSetExternalControl(externalControl);
+ }
+
private class VibrateThread extends Thread {
private final VibrationEffect.Waveform mWaveform;
private final int mUid;
@@ -1290,6 +1342,13 @@ public class VibratorService extends IVibratorService.Stub
} else {
pw.println("null");
}
+ pw.print(" mCurrentExternalVibration=");
+ if (mCurrentExternalVibration != null) {
+ pw.println(mCurrentExternalVibration.toString());
+ } else {
+ pw.println("null");
+ }
+ pw.println(" mVibratorUnderExternalControl=" + mVibratorUnderExternalControl);
pw.println(" mLowPowerMode=" + mLowPowerMode);
pw.println(" mHapticFeedbackIntensity=" + mHapticFeedbackIntensity);
pw.println(" mNotificationIntensity=" + mNotificationIntensity);
@@ -1310,6 +1369,87 @@ public class VibratorService extends IVibratorService.Stub
new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
}
+ final class ExternalVibratorService extends IExternalVibratorService.Stub {
+ @Override
+ public int onExternalVibrationStart(ExternalVibration vib) {
+ if (!mSupportsExternalControl) {
+ return SCALE_MUTE;
+ }
+ if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
+ vib.getUid(), -1 /*owningUid*/, true /*exported*/)
+ != PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid()
+ + " tried to play externally controlled vibration"
+ + " without VIBRATE permission, ignoring.");
+ return SCALE_MUTE;
+ }
+
+ final int scaleLevel;
+ synchronized (mLock) {
+ if (!vib.equals(mCurrentExternalVibration)) {
+ if (mCurrentExternalVibration == null) {
+ // If we're not under external control right now, then cancel any normal
+ // vibration that may be playing and ready the vibrator for external
+ // control.
+ doCancelVibrateLocked();
+ setVibratorUnderExternalControl(true);
+ }
+ // At this point we either have an externally controlled vibration playing, or
+ // no vibration playing. Since the interface defines that only one externally
+ // controlled vibration can play at a time, by returning something other than
+ // SCALE_MUTE from this function we can be assured that if we are currently
+ // playing vibration, it will be muted in favor of the new vibration.
+ //
+ // Note that this doesn't support multiple concurrent external controls, as we
+ // would need to mute the old one still if it came from a different controller.
+ mCurrentExternalVibration = vib;
+ if (DEBUG) {
+ Slog.e(TAG, "Playing external vibration: " + vib);
+ }
+ }
+ final int usage = vib.getAudioAttributes().getUsage();
+ final int defaultIntensity;
+ final int currentIntensity;
+ if (isRingtone(usage)) {
+ defaultIntensity = mVibrator.getDefaultRingVibrationIntensity();
+ currentIntensity = mRingIntensity;
+ } else if (isNotification(usage)) {
+ defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
+ currentIntensity = mNotificationIntensity;
+ } else if (isHapticFeedback(usage)) {
+ defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
+ currentIntensity = mHapticFeedbackIntensity;
+ } else {
+ defaultIntensity = 0;
+ currentIntensity = 0;
+ }
+ scaleLevel = currentIntensity - defaultIntensity;
+ }
+ if (scaleLevel >= SCALE_VERY_LOW && scaleLevel <= SCALE_VERY_HIGH) {
+ return scaleLevel;
+ } else {
+ // Presumably we want to play this but something about our scaling has gone
+ // wrong, so just play with no scaling.
+ Slog.w(TAG, "Error in scaling calculations, ended up with invalid scale level "
+ + scaleLevel + " for vibration " + vib);
+ return SCALE_NONE;
+ }
+ }
+
+ @Override
+ public void onExternalVibrationStop(ExternalVibration vib) {
+ synchronized (mLock) {
+ if (vib.equals(mCurrentExternalVibration)) {
+ mCurrentExternalVibration = null;
+ setVibratorUnderExternalControl(false);
+ if (DEBUG) {
+ Slog.e(TAG, "Stopping external vibration" + vib);
+ }
+ }
+ }
+ }
+ }
+
private final class VibratorShellCommand extends ShellCommand {
private final IBinder mToken;
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 41fedc5fab45..15d66e6e646f 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -29,10 +29,12 @@ import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.AppOpsManager;
import android.app.IActivityTaskManager;
+import android.app.KeyguardManager;
import android.app.TaskStackListener;
import android.app.UserSwitchObserver;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -377,6 +379,13 @@ public class BiometricService extends SystemService {
new BiometricTaskStackListener();
private final Random mRandom = new Random();
+ // TODO(b/123378871): Remove when moved.
+ // When BiometricPrompt#setEnableFallback is set to true, we need to store the client (app)
+ // receiver. BiometricService internally launches CDCA which invokes BiometricService to
+ // start authentication (normal path). When auth is success/rejected, CDCA will use an aidl
+ // method to poke BiometricService - the result will then be forwarded to this receiver.
+ private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver;
+
// The current authentication session, null if idle/done. We need to track both the current
// and pending sessions since errors may be sent to either.
private AuthSession mCurrentAuthSession;
@@ -705,6 +714,22 @@ public class BiometricService extends SystemService {
}
}
+ // Launch CDC instead if necessary. CDC will return results through an AIDL call, since
+ // we can't get activity results. Store the receiver somewhere so we can forward the
+ // result back to the client.
+ // TODO(b/123378871): Remove when moved.
+ if (bundle.getBoolean(BiometricPrompt.KEY_ENABLE_FALLBACK)) {
+ mConfirmDeviceCredentialReceiver = receiver;
+ final KeyguardManager kgm = getContext().getSystemService(KeyguardManager.class);
+ // Use this so we don't need to duplicate logic..
+ final Intent intent = kgm.createConfirmDeviceCredentialIntent(null /* title */,
+ null /* description */);
+ // Then give it the bundle to do magic behavior..
+ intent.putExtra(KeyguardManager.EXTRA_BIOMETRIC_PROMPT_BUNDLE, bundle);
+ getContext().startActivityAsUser(intent, UserHandle.CURRENT);
+ return;
+ }
+
mHandler.post(() -> {
final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId);
final int modality = result.first;
@@ -745,6 +770,36 @@ public class BiometricService extends SystemService {
});
}
+ @Override // Binder call
+ public void onConfirmDeviceCredentialSuccess() {
+ checkInternalPermission();
+ if (mConfirmDeviceCredentialReceiver == null) {
+ Slog.w(TAG, "onCDCASuccess null!");
+ return;
+ }
+ try {
+ mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException", e);
+ }
+ mConfirmDeviceCredentialReceiver = null;
+ }
+
+ @Override // Binder call
+ public void onConfirmDeviceCredentialError(int error, String message) {
+ checkInternalPermission();
+ if (mConfirmDeviceCredentialReceiver == null) {
+ Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message);
+ return;
+ }
+ try {
+ mConfirmDeviceCredentialReceiver.onError(error, message);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "RemoteException", e);
+ }
+ mConfirmDeviceCredentialReceiver = null;
+ }
+
/**
* authenticate() (above) which is called from BiometricPrompt determines which
* modality/modalities to start authenticating with. authenticateInternal() should only be
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 3db6a74a1c6c..fcf821f23ae9 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -48,14 +48,12 @@ import android.os.SELinux;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
-import android.util.StatsLog;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.DumpUtils;
import com.android.server.SystemServerInitThreadPool;
-import com.android.server.biometrics.AuthenticationClient;
import com.android.server.biometrics.BiometricServiceBase;
import com.android.server.biometrics.BiometricUtils;
import com.android.server.biometrics.ClientMonitor;
@@ -588,11 +586,6 @@ public class FingerprintService extends BiometricServiceBase {
public void onAcquired(final long deviceId, final int acquiredInfo, final int vendorCode) {
mHandler.post(() -> {
FingerprintService.super.handleAcquired(deviceId, acquiredInfo, vendorCode);
- if (getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
- && getCurrentClient() instanceof AuthenticationClient) {
- // Ignore enrollment acquisitions or acquisitions when we are locked out.
- StatsLog.write(StatsLog.FINGERPRINT_ACQUIRED, mCurrentUserId, mIsCrypto);
- }
});
}
@@ -602,22 +595,6 @@ public class FingerprintService extends BiometricServiceBase {
mHandler.post(() -> {
Fingerprint fp = new Fingerprint("", groupId, fingerId, deviceId);
FingerprintService.super.handleAuthenticated(fp, token);
- // Send authentication to statsd.
- final boolean authenticated = fingerId != 0;
- StatsLog.write(StatsLog.FINGERPRINT_AUTHENTICATED, mCurrentUserId, mIsCrypto,
- authenticated);
- if (!authenticated) {
- // If we failed to authenticate because of a lockout, inform statsd.
- final int lockoutMode = getLockoutMode();
- if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
- StatsLog.write(StatsLog.FINGERPRINT_ERROR_OCCURRED, mCurrentUserId,
- mIsCrypto, StatsLog.FINGERPRINT_ERROR_OCCURRED__ERROR__LOCKOUT);
- } else if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
- StatsLog.write(StatsLog.FINGERPRINT_ERROR_OCCURRED, mCurrentUserId,
- mIsCrypto,
- StatsLog.FINGERPRINT_ERROR_OCCURRED__ERROR__PERMANENT_LOCKOUT);
- }
- }
});
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index cb3f91b7b6bb..b89768ac4b68 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -36,6 +36,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.ColorSpace;
import android.graphics.Point;
import android.hardware.SensorManager;
import android.hardware.display.AmbientBrightnessDayStats;
@@ -93,9 +94,9 @@ import com.android.server.DisplayThread;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.UiThread;
+import com.android.server.display.ColorDisplayService.ColorDisplayServiceInternal;
import com.android.server.wm.SurfaceAnimationThread;
import com.android.server.wm.WindowManagerInternal;
-import com.android.server.display.ColorDisplayService.ColorDisplayServiceInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -294,6 +295,7 @@ public final class DisplayManagerService extends SystemService {
// is rejected by the system.
private final Curve mMinimumBrightnessCurve;
private final Spline mMinimumBrightnessSpline;
+ private final ColorSpace mWideColorSpace;
public DisplayManagerService(Context context) {
this(context, new Injector());
@@ -322,6 +324,8 @@ public final class DisplayManagerService extends SystemService {
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
mCurrentUserId = UserHandle.USER_SYSTEM;
+ ColorSpace[] colorSpaces = SurfaceControl.getCompositionColorSpaces();
+ mWideColorSpace = colorSpaces[1];
}
public void setupSchedulerPolicies() {
@@ -1073,6 +1077,10 @@ public final class DisplayManagerService extends SystemService {
return mMinimumBrightnessCurve;
}
+ int getPreferredWideGamutColorSpaceIdInternal() {
+ return mWideColorSpace.getId();
+ }
+
private void setBrightnessConfigurationForUserInternal(
@Nullable BrightnessConfiguration c, @UserIdInt int userId,
@Nullable String packageName) {
@@ -2128,6 +2136,16 @@ public final class DisplayManagerService extends SystemService {
}
}
+ @Override // Binder call
+ public int getPreferredWideGamutColorSpaceId() {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return getPreferredWideGamutColorSpaceIdInternal();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
void setBrightness(int brightness) {
Settings.System.putIntForUser(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS, brightness, UserHandle.USER_CURRENT);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index cfc85dac8a53..4349b4aa3603 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -34,6 +34,7 @@ import android.os.UserManagerInternal;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.IntArray;
import android.util.Pair;
import android.util.Printer;
@@ -756,6 +757,14 @@ final class InputMethodUtils {
*/
private final ArrayMap<String, String> mCopyOnWriteDataStore = new ArrayMap<>();
+ private static final ArraySet<String> CLONE_TO_MANAGED_PROFILE = new ArraySet<>();
+ static {
+ Settings.Secure.getCloneToManagedProfileSettings(CLONE_TO_MANAGED_PROFILE);
+ }
+
+ private static final UserManagerInternal sUserManagerInternal =
+ LocalServices.getService(UserManagerInternal.class);
+
private boolean mCopyOnWrite = false;
@NonNull
private String mEnabledInputMethodsStrCache = "";
@@ -833,7 +842,9 @@ final class InputMethodUtils {
if (mCopyOnWrite) {
mCopyOnWriteDataStore.put(key, str);
} else {
- Settings.Secure.putStringForUser(mResolver, key, str, mCurrentUserId);
+ final int userId = CLONE_TO_MANAGED_PROFILE.contains(key)
+ ? sUserManagerInternal.getProfileParentId(mCurrentUserId) : mCurrentUserId;
+ Settings.Secure.putStringForUser(mResolver, key, str, userId);
}
}
@@ -852,14 +863,16 @@ final class InputMethodUtils {
if (mCopyOnWrite) {
mCopyOnWriteDataStore.put(key, String.valueOf(value));
} else {
- Settings.Secure.putIntForUser(mResolver, key, value, mCurrentUserId);
+ final int userId = CLONE_TO_MANAGED_PROFILE.contains(key)
+ ? sUserManagerInternal.getProfileParentId(mCurrentUserId) : mCurrentUserId;
+ Settings.Secure.putIntForUser(mResolver, key, value, userId);
}
}
private int getInt(String key, int defaultValue) {
if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) {
final String result = mCopyOnWriteDataStore.get(key);
- return result != null ? Integer.parseInt(result) : 0;
+ return result != null ? Integer.parseInt(result) : defaultValue;
}
return Settings.Secure.getIntForUser(mResolver, key, defaultValue, mCurrentUserId);
}
diff --git a/services/core/java/com/android/server/location/GeocoderProxy.java b/services/core/java/com/android/server/location/GeocoderProxy.java
index f1de37188510..e6f0ed9d14b0 100644
--- a/services/core/java/com/android/server/location/GeocoderProxy.java
+++ b/services/core/java/com/android/server/location/GeocoderProxy.java
@@ -20,8 +20,6 @@ import android.content.Context;
import android.location.Address;
import android.location.GeocoderParams;
import android.location.IGeocodeProvider;
-import android.os.RemoteException;
-import android.util.Log;
import com.android.internal.os.BackgroundThread;
import com.android.server.ServiceWatcher;
@@ -68,35 +66,22 @@ public class GeocoderProxy {
public String getFromLocation(double latitude, double longitude, int maxResults,
GeocoderParams params, List<Address> addrs) {
- final String[] result = new String[]{"Service not Available"};
- mServiceWatcher.runOnBinder(binder -> {
+ return mServiceWatcher.runOnBinderBlocking(binder -> {
IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
- try {
- result[0] = provider.getFromLocation(
- latitude, longitude, maxResults, params, addrs);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
- });
- return result[0];
+ return provider.getFromLocation(latitude, longitude, maxResults, params, addrs);
+ }, "Service not Available");
}
public String getFromLocationName(String locationName,
double lowerLeftLatitude, double lowerLeftLongitude,
double upperRightLatitude, double upperRightLongitude, int maxResults,
GeocoderParams params, List<Address> addrs) {
- final String[] result = new String[]{"Service not Available"};
- mServiceWatcher.runOnBinder(binder -> {
+ return mServiceWatcher.runOnBinderBlocking(binder -> {
IGeocodeProvider provider = IGeocodeProvider.Stub.asInterface(binder);
- try {
- result[0] = provider.getFromLocationName(locationName, lowerLeftLatitude,
- lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
- maxResults, params, addrs);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
- });
- return result[0];
+ return provider.getFromLocationName(locationName, lowerLeftLatitude,
+ lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
+ maxResults, params, addrs);
+ }, "Service not Available");
}
}
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index a6da8c5e7713..6b5b1bebd20f 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -127,20 +127,16 @@ public class LocationProviderProxy extends AbstractLocationProvider {
return mServiceWatcher.start();
}
- private void initializeService(IBinder binder) {
+ private void initializeService(IBinder binder) throws RemoteException {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
if (D) Log.d(TAG, "applying state to connected service " + mServiceWatcher);
- try {
- service.setLocationProviderManager(mManager);
+ service.setLocationProviderManager(mManager);
- synchronized (mRequestLock) {
- if (mRequest != null) {
- service.setRequest(mRequest, mWorkSource);
- }
+ synchronized (mRequestLock) {
+ if (mRequest != null) {
+ service.setRequest(mRequest, mWorkSource);
}
- } catch (RemoteException e) {
- Log.w(TAG, e);
}
}
@@ -157,63 +153,44 @@ public class LocationProviderProxy extends AbstractLocationProvider {
}
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- service.setRequest(request, source);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
+ service.setRequest(request, source);
});
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(" service=" + mServiceWatcher);
- mServiceWatcher.runOnBinder(binder -> {
+ mServiceWatcher.runOnBinderBlocking(binder -> {
try {
TransferPipe.dumpAsync(binder, fd, args);
} catch (IOException | RemoteException e) {
- pw.println(" failed to dump location provider: " + e);
+ pw.println(" failed to dump location provider");
}
- });
+ return null;
+ }, null);
}
@Override
public int getStatus(Bundle extras) {
- int[] status = new int[] {LocationProvider.TEMPORARILY_UNAVAILABLE};
- mServiceWatcher.runOnBinder(binder -> {
+ return mServiceWatcher.runOnBinderBlocking(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- status[0] = service.getStatus(extras);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
- });
- return status[0];
+ return service.getStatus(extras);
+ }, LocationProvider.TEMPORARILY_UNAVAILABLE);
}
@Override
public long getStatusUpdateTime() {
- long[] updateTime = new long[] {0L};
- mServiceWatcher.runOnBinder(binder -> {
+ return mServiceWatcher.runOnBinderBlocking(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- updateTime[0] = service.getStatusUpdateTime();
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
- });
- return updateTime[0];
+ return service.getStatusUpdateTime();
+ }, 0L);
}
@Override
public void sendExtraCommand(String command, Bundle extras) {
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- try {
- service.sendExtraCommand(command, extras);
- } catch (RemoteException e) {
- Log.w(TAG, e);
- }
+ service.sendExtraCommand(command, extras);
});
}
}
diff --git a/services/core/java/com/android/server/location/OWNERS b/services/core/java/com/android/server/location/OWNERS
index 92b4d5fea113..c2c95e6042de 100644
--- a/services/core/java/com/android/server/location/OWNERS
+++ b/services/core/java/com/android/server/location/OWNERS
@@ -1,6 +1,8 @@
+aadmal@google.com
arthuri@google.com
bduddie@google.com
gomo@google.com
sooniln@google.com
weiwa@google.com
wyattriley@google.com
+yuhany@google.com
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index a1646862de9f..de3f50ad8c2c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1087,7 +1087,8 @@ public class NotificationManagerService extends SystemService {
|| (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
|| action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
|| action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
- || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
+ || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)
+ || action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_ALL);
String pkgList[] = null;
@@ -1108,6 +1109,23 @@ public class NotificationManagerService extends SystemService {
uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
cancelNotifications = false;
unhideNotifications = true;
+ } else if (action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
+ final int distractionRestrictions =
+ intent.getIntExtra(Intent.EXTRA_DISTRACTION_RESTRICTIONS,
+ PackageManager.RESTRICTION_NONE);
+ if ((distractionRestrictions
+ & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0) {
+ pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
+ cancelNotifications = false;
+ hideNotifications = true;
+ } else {
+ pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
+ cancelNotifications = false;
+ unhideNotifications = true;
+ }
+
} else if (queryRestart) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
@@ -1651,6 +1669,7 @@ public class NotificationManagerService extends SystemService {
IntentFilter suspendedPkgFilter = new IntentFilter();
suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
+ suspendedPkgFilter.addAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
suspendedPkgFilter, null, null);
@@ -7743,6 +7762,20 @@ public class NotificationManagerService extends SystemService {
mPackageIntentReceiver.onReceive(getContext(), intent);
}
+ @VisibleForTesting
+ protected void simulatePackageDistractionBroadcast(int flag, String[] pkgs) {
+ // only use for testing: mimic receive broadcast that package is (un)distracting
+ // but does not actually register that info with packagemanager
+ final Bundle extras = new Bundle();
+ extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs);
+ extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag);
+
+ final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
+ intent.putExtras(extras);
+
+ mPackageIntentReceiver.onReceive(getContext(), intent);
+ }
+
/**
* Wrapper for a StatusBarNotification object that allows transfer across a oneway
* binder without sending large amounts of data over a oneway transaction.
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index ac965faedd34..ab49ebb66fbf 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -667,15 +667,15 @@ public final class NotificationRecord {
getUserSentiment()));
}
}
- if (signals.containsKey(Adjustment.KEY_SMART_ACTIONS)) {
+ if (signals.containsKey(Adjustment.KEY_CONTEXTUAL_ACTIONS)) {
setSystemGeneratedSmartActions(
- signals.getParcelableArrayList(Adjustment.KEY_SMART_ACTIONS));
+ signals.getParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS));
MetricsLogger.action(getAdjustmentLogMaker()
.addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SMART_ACTIONS,
getSystemGeneratedSmartActions().size()));
}
- if (signals.containsKey(Adjustment.KEY_SMART_REPLIES)) {
- setSmartReplies(signals.getCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES));
+ if (signals.containsKey(Adjustment.KEY_TEXT_REPLIES)) {
+ setSmartReplies(signals.getCharSequenceArrayList(Adjustment.KEY_TEXT_REPLIES));
MetricsLogger.action(getAdjustmentLogMaker()
.addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SMART_REPLIES,
getSmartReplies().size()));
diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java
index 3d88f20f0710..2aaa1edcfad9 100644
--- a/services/core/java/com/android/server/notification/NotificationShellCmd.java
+++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java
@@ -176,6 +176,14 @@ public class NotificationShellCmd extends ShellCommand {
// only use for testing
mDirectService.simulatePackageSuspendBroadcast(false, getNextArgRequired());
}
+ case "distract_package": {
+ // only use for testing
+ // Flag values are in
+ // {@link android.content.pm.PackageManager.DistractionRestriction}.
+ mDirectService.simulatePackageDistractionBroadcast(
+ Integer.parseInt(getNextArgRequired()),
+ getNextArgRequired().split(","));
+ }
break;
case "post":
case "notify":
diff --git a/services/core/java/com/android/server/role/FinancialSmsManager.java b/services/core/java/com/android/server/role/FinancialSmsManager.java
new file mode 100644
index 000000000000..2ec39931789a
--- /dev/null
+++ b/services/core/java/com/android/server/role/FinancialSmsManager.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.role;
+
+import android.Manifest;
+import android.annotation.MainThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.sms.FinancialSmsService;
+import android.service.sms.IFinancialSmsService;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * This class binds to {@code FinancialSmsService}.
+ */
+final class FinancialSmsManager {
+
+ private static final String TAG = "FinancialSmsManager";
+
+ private final Context mContext;
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private ServiceConnection mServiceConnection;
+
+ @GuardedBy("mLock")
+ private IFinancialSmsService mRemoteService;
+
+ @GuardedBy("mLock")
+ private ArrayList<Command> mQueuedCommands;
+
+ FinancialSmsManager(Context context) {
+ mContext = context;
+ }
+
+ @Nullable
+ ServiceInfo getServiceInfo() {
+ final String packageName =
+ mContext.getPackageManager().getServicesSystemSharedLibraryPackageName();
+ if (packageName == null) {
+ Slog.w(TAG, "no external services package!");
+ return null;
+ }
+
+ final Intent intent = new Intent(FinancialSmsService.ACTION_FINANCIAL_SERVICE_INTENT);
+ intent.setPackage(packageName);
+ final ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent,
+ PackageManager.GET_SERVICES);
+ if (resolveInfo == null || resolveInfo.serviceInfo == null) {
+ Slog.w(TAG, "No valid components found.");
+ return null;
+ }
+ return resolveInfo.serviceInfo;
+ }
+
+ @Nullable
+ private ComponentName getServiceComponentName() {
+ final ServiceInfo serviceInfo = getServiceInfo();
+ if (serviceInfo == null) return null;
+
+ final ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name);
+ if (!Manifest.permission.BIND_FINANCIAL_SMS_SERVICE.equals(serviceInfo.permission)) {
+ Slog.w(TAG, name.flattenToShortString() + " does not require permission "
+ + Manifest.permission.BIND_FINANCIAL_SMS_SERVICE);
+ return null;
+ }
+
+ return name;
+ }
+
+ void reset() {
+ synchronized (mLock) {
+ if (mServiceConnection != null) {
+ mContext.unbindService(mServiceConnection);
+ mServiceConnection = null;
+ } else {
+ Slog.d(TAG, "reset(): service is not bound. Do nothing.");
+ }
+ }
+ }
+
+ /**
+ * Run a command, starting the service connection if necessary.
+ */
+ private void connectAndRun(@NonNull Command command) {
+ synchronized (mLock) {
+ if (mRemoteService != null) {
+ try {
+ command.run(mRemoteService);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "exception calling service: " + e);
+ }
+ return;
+ } else {
+ if (mQueuedCommands == null) {
+ mQueuedCommands = new ArrayList<>(1);
+ }
+ mQueuedCommands.add(command);
+ // If we're already connected, don't create a new connection, just leave - the
+ // command will be run when the service connects
+ if (mServiceConnection != null) return;
+ }
+
+ // Create the connection
+ mServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mLock) {
+ mRemoteService = IFinancialSmsService.Stub.asInterface(service);
+ if (mQueuedCommands != null) {
+ final int size = mQueuedCommands.size();
+ for (int i = 0; i < size; i++) {
+ final Command queuedCommand = mQueuedCommands.get(i);
+ try {
+ queuedCommand.run(mRemoteService);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "exception calling " + name + ": " + e);
+ }
+ }
+ mQueuedCommands = null;
+ }
+ }
+ }
+
+ @Override
+ @MainThread
+ public void onServiceDisconnected(ComponentName name) {
+ synchronized (mLock) {
+ mRemoteService = null;
+ }
+ }
+
+ @Override
+ public void onBindingDied(ComponentName name) {
+ synchronized (mLock) {
+ mRemoteService = null;
+ }
+ }
+
+ @Override
+ public void onNullBinding(ComponentName name) {
+ synchronized (mLock) {
+ mRemoteService = null;
+ }
+ }
+ };
+
+ final ComponentName component = getServiceComponentName();
+ if (component != null) {
+ final Intent intent = new Intent();
+ intent.setComponent(component);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mContext.bindServiceAsUser(intent, mServiceConnection, Context.BIND_AUTO_CREATE,
+ UserHandle.getUserHandleForUid(UserHandle.getCallingUserId()));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+ }
+
+ void getSmsMessages(RemoteCallback callback, @Nullable Bundle params) {
+ connectAndRun((service) -> service.getSmsMessages(callback, params));
+ }
+
+ void dump(String prefix, PrintWriter pw) {
+ final ComponentName impl = getServiceComponentName();
+ pw.print(prefix); pw.print("User ID: "); pw.println(UserHandle.getCallingUserId());
+ pw.print(prefix); pw.print("Queued commands: ");
+ if (mQueuedCommands == null) {
+ pw.println("N/A");
+ } else {
+ pw.println(mQueuedCommands.size());
+ }
+ pw.print(prefix); pw.print("Implementation: ");
+ if (impl == null) {
+ pw.println("N/A");
+ return;
+ }
+ pw.println(impl.flattenToShortString());
+ }
+
+ private interface Command {
+ void run(IFinancialSmsService service) throws RemoteException;
+ }
+}
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 1c7596b80fd7..7d8c7c9ee0d5 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -33,16 +33,24 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.PermissionChecker;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
+import android.database.CursorWindow;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
+import android.os.RemoteCallback;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManagerInternal;
+import android.service.sms.FinancialSmsService;
+import android.telephony.IFinancialSmsCallback;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.PackageUtils;
@@ -620,5 +628,51 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
dumpOutputStream.flush();
}
+
+ /**
+ * Get filtered SMS messages for financial app.
+ */
+ @Override
+ public void getSmsMessagesForFinancialApp(
+ String callingPkg, Bundle params, IFinancialSmsCallback callback) {
+ int mode = PermissionChecker.checkCallingOrSelfPermission(
+ getContext(),
+ AppOpsManager.OPSTR_SMS_FINANCIAL_TRANSACTIONS);
+
+ if (mode == PermissionChecker.PERMISSION_GRANTED) {
+ FinancialSmsManager financialSmsManager = new FinancialSmsManager(getContext());
+ financialSmsManager.getSmsMessages(new RemoteCallback((result) -> {
+ CursorWindow messages = null;
+ if (result == null) {
+ Slog.w(LOG_TAG, "result is null.");
+ } else {
+ messages = result.getParcelable(FinancialSmsService.EXTRA_SMS_MSGS);
+ }
+ try {
+ callback.onGetSmsMessagesForFinancialApp(messages);
+ } catch (RemoteException e) {
+ // do nothing
+ }
+ }), params);
+ } else {
+ try {
+ callback.onGetSmsMessagesForFinancialApp(null);
+ } catch (RemoteException e) {
+ // do nothing
+ }
+ }
+ }
+
+ private int getUidForPackage(String packageName) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return getContext().getPackageManager().getApplicationInfo(packageName,
+ PackageManager.MATCH_ANY_USER).uid;
+ } catch (NameNotFoundException nnfe) {
+ return -1;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 8b4c410000bb..e59228a16fb1 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -28,7 +28,6 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
-import android.content.pm.StringParceledListSlice;
import android.content.pm.VersionedPackage;
import android.content.rollback.IRollbackManager;
import android.content.rollback.PackageRollbackInfo;
@@ -56,12 +55,10 @@ import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
-import java.util.Set;
/**
* Implementation of service that manages APK level rollbacks.
@@ -200,48 +197,20 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
@Override
- public RollbackInfo getAvailableRollback(String packageName) {
+ public ParceledListSlice getAvailableRollbacks() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_ROLLBACKS,
- "getAvailableRollback");
+ "getAvailableRollbacks");
- RollbackData data = getRollbackForPackage(packageName);
- if (data == null) {
- return null;
- }
-
- // Note: The rollback for the package ought to be for the currently
- // installed version, otherwise the rollback data is out of date. In
- // that rare case, we'll check when we execute the rollback whether
- // it's out of date or not, so no need to check package versions here.
-
- for (PackageRollbackInfo info : data.packages) {
- if (info.getPackageName().equals(packageName)) {
- // TODO: Once the RollbackInfo API supports info about
- // dependant packages, add that info here.
- return new RollbackInfo(data.rollbackId, info);
- }
- }
- return null;
- }
-
- @Override
- public StringParceledListSlice getPackagesWithAvailableRollbacks() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.MANAGE_ROLLBACKS,
- "getPackagesWithAvailableRollbacks");
-
- final Set<String> packageNames = new HashSet<>();
synchronized (mLock) {
ensureRollbackDataLoadedLocked();
+ List<RollbackInfo> rollbacks = new ArrayList<>();
for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
RollbackData data = mAvailableRollbacks.get(i);
- for (PackageRollbackInfo info : data.packages) {
- packageNames.add(info.getPackageName());
- }
+ rollbacks.add(new RollbackInfo(data.rollbackId, data.packages));
}
+ return new ParceledListSlice<>(rollbacks);
}
- return new StringParceledListSlice(new ArrayList<>(packageNames));
}
@Override
@@ -258,7 +227,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
@Override
- public void executeRollback(RollbackInfo rollback, String callerPackageName,
+ public void commitRollback(int rollbackId, String callerPackageName,
IntentSender statusReceiver) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_ROLLBACKS,
@@ -269,28 +238,21 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
appOps.checkPackage(callingUid, callerPackageName);
getHandler().post(() ->
- executeRollbackInternal(rollback, callerPackageName, statusReceiver));
+ commitRollbackInternal(rollbackId, callerPackageName, statusReceiver));
}
/**
- * Performs the actual work to execute a rollback.
+ * Performs the actual work to commit a rollback.
* The work is done on the current thread. This may be a long running
* operation.
*/
- private void executeRollbackInternal(RollbackInfo rollback,
+ private void commitRollbackInternal(int rollbackId,
String callerPackageName, IntentSender statusReceiver) {
- String targetPackageName = rollback.targetPackage.getPackageName();
- Log.i(TAG, "Initiating rollback of " + targetPackageName);
+ Log.i(TAG, "Initiating rollback");
- // Get the latest RollbackData for the target package.
- final RollbackData data = getRollbackForPackage(targetPackageName);
+ RollbackData data = getRollbackForId(rollbackId);
if (data == null) {
- sendFailure(statusReceiver, "No rollback available for package.");
- return;
- }
-
- if (data.rollbackId != rollback.getRollbackId()) {
- sendFailure(statusReceiver, "Rollback for package is out of date.");
+ sendFailure(statusReceiver, "Rollback unavailable");
return;
}
@@ -335,14 +297,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
PackageManager pm = context.getPackageManager();
try {
PackageInstaller packageInstaller = pm.getPackageInstaller();
- String installerPackageName = pm.getInstallerPackageName(targetPackageName);
- if (installerPackageName == null) {
- sendFailure(statusReceiver, "Cannot find installer package");
- return;
- }
PackageInstaller.SessionParams parentParams = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- parentParams.setInstallerPackageName(installerPackageName);
parentParams.setAllowDowngrade(true);
parentParams.setMultiPackage();
int parentSessionId = packageInstaller.createSession(parentParams);
@@ -351,6 +307,11 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
for (PackageRollbackInfo info : data.packages) {
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
+ String installerPackageName = pm.getInstallerPackageName(info.getPackageName());
+ if (installerPackageName == null) {
+ sendFailure(statusReceiver, "Cannot find installer package");
+ return;
+ }
params.setInstallerPackageName(installerPackageName);
params.setAllowDowngrade(true);
int sessionId = packageInstaller.createSession(params);
@@ -389,10 +350,11 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
return;
}
- addRecentlyExecutedRollback(rollback);
+ addRecentlyExecutedRollback(
+ new RollbackInfo(data.rollbackId, data.packages));
sendSuccess(statusReceiver);
- Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
+ Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
// TODO: This call emits the warning "Calling a method in the
// system process without a qualified user". Fix that.
@@ -406,7 +368,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
data.inProgress = true;
parentSession.commit(receiver.getIntentSender());
} catch (IOException e) {
- Log.e(TAG, "Unable to roll back " + targetPackageName, e);
+ Log.e(TAG, "Rollback failed", e);
sendFailure(statusReceiver, "IOException: " + e.toString());
return;
}
@@ -537,9 +499,12 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
boolean changed = false;
while (iter.hasNext()) {
RollbackInfo rollback = iter.next();
- if (packageName.equals(rollback.targetPackage.getPackageName())) {
- iter.remove();
- changed = true;
+ for (PackageRollbackInfo info : rollback.getPackages()) {
+ if (packageName.equals(info.getPackageName())) {
+ iter.remove();
+ changed = true;
+ break;
+ }
}
}
@@ -935,6 +900,25 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
return null;
}
+ /*
+ * Returns the RollbackData, if any, for an available rollback with the
+ * given rollbackId.
+ */
+ private RollbackData getRollbackForId(int rollbackId) {
+ synchronized (mLock) {
+ // TODO: Have ensureRollbackDataLoadedLocked return the list of
+ // available rollbacks, to hopefully avoid forgetting to call it?
+ ensureRollbackDataLoadedLocked();
+ for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
+ RollbackData data = mAvailableRollbacks.get(i);
+ if (data.rollbackId == rollbackId) {
+ return data;
+ }
+ }
+ }
+ return null;
+ }
+
@GuardedBy("mLock")
private int allocateRollbackIdLocked() throws IOException {
int n = 0;
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 1f2f1ccd7383..fcae61895b36 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -19,6 +19,7 @@ package com.android.server.rollback;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
+import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.os.Handler;
@@ -26,6 +27,7 @@ import android.os.HandlerThread;
import com.android.server.PackageWatchdog;
import com.android.server.PackageWatchdog.PackageHealthObserver;
+import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
import java.util.List;
@@ -38,10 +40,12 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
private static final String TAG = "RollbackPackageHealthObserver";
private static final String NAME = "rollback-observer";
private Context mContext;
+ private RollbackManager mRollbackManager;
private Handler mHandler;
RollbackPackageHealthObserver(Context context) {
mContext = context;
+ mRollbackManager = mContext.getSystemService(RollbackManager.class);
HandlerThread handlerThread = new HandlerThread("RollbackPackageHealthObserver");
handlerThread.start();
mHandler = handlerThread.getThreadHandler();
@@ -49,16 +53,48 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
}
@Override
- public boolean onHealthCheckFailed(String packageName) {
- RollbackManager rollbackManager = mContext.getSystemService(RollbackManager.class);
- RollbackInfo rollback = rollbackManager.getAvailableRollback(packageName);
- if (rollback != null) {
- // TODO(zezeozue): Only rollback if rollback version == failed package version
- mHandler.post(() -> executeRollback(rollbackManager, rollback));
- return true;
+ public int onHealthCheckFailed(String packageName) {
+ RollbackInfo rollback = getAvailableRollback(packageName);
+ if (rollback == null) {
+ // Don't handle the notification, no rollbacks available for the package
+ return PackageHealthObserverImpact.USER_IMPACT_NONE;
}
- // Don't handle the notification, no rollbacks available
- return false;
+ // Rollback is available, we may get a callback into #execute
+ return PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
+ }
+
+ @Override
+ public boolean execute(String packageName) {
+ RollbackInfo rollback = getAvailableRollback(packageName);
+ if (rollback == null) {
+ // Expected a rollback to be available, what happened?
+ return false;
+ }
+
+ // TODO(zezeozue): Only rollback if rollback version == failed package version
+ LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
+ int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ if (status == PackageInstaller.STATUS_SUCCESS) {
+ // TODO(zezeozue); Log success metrics
+ // Rolledback successfully, no action required by other observers
+ } else {
+ // TODO(zezeozue); Log failure metrics
+ // Rollback failed other observers should have a shot
+ }
+ });
+
+ // TODO(zezeozue): Log initiated metrics
+ mHandler.post(() ->
+ mRollbackManager.commitRollback(rollback.getRollbackId(),
+ rollbackReceiver.getIntentSender()));
+ // Assume rollback executed successfully
+ return true;
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
}
/**
@@ -69,26 +105,15 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve
PackageWatchdog.getInstance(mContext).startObservingHealth(this, packages, durationMs);
}
- private void executeRollback(RollbackManager manager, RollbackInfo rollback) {
- // TODO(zezeozue): Log initiated metrics
- LocalIntentReceiver rollbackReceiver = new LocalIntentReceiver((Intent result) -> {
- mHandler.post(() -> {
- int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE);
- if (status == PackageInstaller.STATUS_SUCCESS) {
- // TODO(zezeozue); Log success metrics
- // Rolledback successfully, no action required by other observers
- } else {
- // TODO(zezeozue); Log failure metrics
- // Rollback failed other observers should have a shot
+ private RollbackInfo getAvailableRollback(String packageName) {
+ for (RollbackInfo rollback : mRollbackManager.getAvailableRollbacks()) {
+ for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
+ if (packageName.equals(packageRollback.getPackageName())) {
+ // TODO(zezeozue): Only rollback if rollback version == failed package version
+ return rollback;
}
- });
- });
- manager.executeRollback(rollback, rollbackReceiver.getIntentSender());
- }
-
- @Override
- public String getName() {
- return NAME;
+ }
+ }
+ return null;
}
}
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 7738be9d32bb..3b24b3e9a444 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -114,13 +114,9 @@ class RollbackStore {
for (int i = 0; i < array.length(); ++i) {
JSONObject element = array.getJSONObject(i);
int rollbackId = element.getInt("rollbackId");
- String packageName = element.getString("packageName");
- long higherVersionCode = element.getLong("higherVersionCode");
- long lowerVersionCode = element.getLong("lowerVersionCode");
- PackageRollbackInfo target = new PackageRollbackInfo(
- new VersionedPackage(packageName, higherVersionCode),
- new VersionedPackage(packageName, lowerVersionCode));
- RollbackInfo rollback = new RollbackInfo(rollbackId, target);
+ List<PackageRollbackInfo> packages = packageRollbackInfosFromJson(
+ element.getJSONArray("packages"));
+ RollbackInfo rollback = new RollbackInfo(rollbackId, packages);
recentlyExecutedRollbacks.add(rollback);
}
} catch (IOException | JSONException e) {
@@ -155,18 +151,8 @@ class RollbackStore {
void saveAvailableRollback(RollbackData data) throws IOException {
try {
JSONObject dataJson = new JSONObject();
- JSONArray packagesJson = new JSONArray();
- for (PackageRollbackInfo info : data.packages) {
- JSONObject infoJson = new JSONObject();
- infoJson.put("packageName", info.getPackageName());
- infoJson.put("higherVersionCode",
- info.getVersionRolledBackFrom().getLongVersionCode());
- infoJson.put("lowerVersionCode",
- info.getVersionRolledBackTo().getVersionCode());
- packagesJson.put(infoJson);
- }
dataJson.put("rollbackId", data.rollbackId);
- dataJson.put("packages", packagesJson);
+ dataJson.put("packages", toJson(data.packages));
dataJson.put("timestamp", data.timestamp.toString());
PrintWriter pw = new PrintWriter(new File(data.backupDir, "rollback.json"));
@@ -200,11 +186,7 @@ class RollbackStore {
RollbackInfo rollback = recentlyExecutedRollbacks.get(i);
JSONObject element = new JSONObject();
element.put("rollbackId", rollback.getRollbackId());
- element.put("packageName", rollback.targetPackage.getPackageName());
- element.put("higherVersionCode",
- rollback.targetPackage.getVersionRolledBackFrom().getLongVersionCode());
- element.put("lowerVersionCode",
- rollback.targetPackage.getVersionRolledBackTo().getLongVersionCode());
+ element.put("packages", toJson(rollback.getPackages()));
array.put(element);
}
@@ -229,18 +211,7 @@ class RollbackStore {
int rollbackId = dataJson.getInt("rollbackId");
RollbackData data = new RollbackData(rollbackId, backupDir);
-
- JSONArray packagesJson = dataJson.getJSONArray("packages");
- for (int i = 0; i < packagesJson.length(); ++i) {
- JSONObject infoJson = packagesJson.getJSONObject(i);
- String packageName = infoJson.getString("packageName");
- long higherVersionCode = infoJson.getLong("higherVersionCode");
- long lowerVersionCode = infoJson.getLong("lowerVersionCode");
- data.packages.add(new PackageRollbackInfo(
- new VersionedPackage(packageName, higherVersionCode),
- new VersionedPackage(packageName, lowerVersionCode)));
- }
-
+ data.packages.addAll(packageRollbackInfosFromJson(dataJson.getJSONArray("packages")));
data.timestamp = Instant.parse(dataJson.getString("timestamp"));
return data;
} catch (JSONException | DateTimeParseException e) {
@@ -248,6 +219,40 @@ class RollbackStore {
}
}
+ private JSONObject toJson(PackageRollbackInfo info) throws JSONException {
+ JSONObject json = new JSONObject();
+ json.put("packageName", info.getPackageName());
+ json.put("higherVersionCode", info.getVersionRolledBackFrom().getLongVersionCode());
+ json.put("lowerVersionCode", info.getVersionRolledBackTo().getLongVersionCode());
+ return json;
+ }
+
+ private PackageRollbackInfo packageRollbackInfoFromJson(JSONObject json) throws JSONException {
+ String packageName = json.getString("packageName");
+ long higherVersionCode = json.getLong("higherVersionCode");
+ long lowerVersionCode = json.getLong("lowerVersionCode");
+ return new PackageRollbackInfo(
+ new VersionedPackage(packageName, higherVersionCode),
+ new VersionedPackage(packageName, lowerVersionCode));
+ }
+
+ private JSONArray toJson(List<PackageRollbackInfo> infos) throws JSONException {
+ JSONArray json = new JSONArray();
+ for (PackageRollbackInfo info : infos) {
+ json.put(toJson(info));
+ }
+ return json;
+ }
+
+ private List<PackageRollbackInfo> packageRollbackInfosFromJson(JSONArray json)
+ throws JSONException {
+ List<PackageRollbackInfo> infos = new ArrayList<>();
+ for (int i = 0; i < json.length(); ++i) {
+ infos.add(packageRollbackInfoFromJson(json.getJSONObject(i)));
+ }
+ return infos;
+ }
+
/**
* Deletes a file completely.
* If the file is a directory, its contents are deleted as well.
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 9135d1db7676..c6d2870a24c9 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -1897,7 +1897,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
pullCategorySize(tagId, elapsedNanos, wallClockNanos, ret);
break;
}
- case StatsLog.NUM_FINGERPRINTS: {
+ case StatsLog.NUM_FINGERPRINTS_ENROLLED: {
pullNumFingerprints(tagId, elapsedNanos, wallClockNanos, ret);
break;
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index a66f0caee56c..b9b5aae03587 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -100,4 +100,11 @@ public interface StatusBarManagerInternal {
* @param rotation rotation suggestion
*/
void onProposedRotationChanged(int rotation, boolean isValid);
+
+ /**
+ * Notifies System UI that the display is ready to show system decorations.
+ *
+ * @param displayId display ID
+ */
+ void onDisplayReady(int displayId);
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 8d2bab43875d..7e87c29e7a58 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -443,6 +443,15 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
} catch (RemoteException ex) {}
}
}
+
+ @Override
+ public void onDisplayReady(int displayId) {
+ if (mBar != null) {
+ try {
+ mBar.onDisplayReady(displayId);
+ } catch (RemoteException ex) { }
+ }
+ }
};
private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() {
diff --git a/services/core/java/com/android/server/testharness/TestHarnessModeService.java b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
index 23c042a57ac8..4adce586e9a5 100644
--- a/services/core/java/com/android/server/testharness/TestHarnessModeService.java
+++ b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
@@ -66,6 +66,7 @@ public class TestHarnessModeService extends SystemService {
private static final String TEST_HARNESS_MODE_PROPERTY = "persist.sys.test_harness";
private PersistentDataBlockManagerInternal mPersistentDataBlockManagerInternal;
+ private boolean mShouldSetUpTestHarnessMode;
public TestHarnessModeService(Context context) {
super(context);
@@ -96,6 +97,7 @@ public class TestHarnessModeService extends SystemService {
// There's no data to apply, so leave it as-is.
return;
}
+ mShouldSetUpTestHarnessMode = true;
PersistentData persistentData = PersistentData.fromBytes(testHarnessModeData);
SystemProperties.set(TEST_HARNESS_MODE_PROPERTY, persistentData.mEnabled ? "1" : "0");
@@ -124,6 +126,9 @@ public class TestHarnessModeService extends SystemService {
}
private void disableAutoSync() {
+ if (!mShouldSetUpTestHarnessMode) {
+ return;
+ }
UserInfo primaryUser = UserManager.get(getContext()).getPrimaryUser();
ContentResolver
.setMasterSyncAutomaticallyAsUser(false, primaryUser.getUserHandle().getIdentifier());
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 69040a2ea974..b0ef8a0d4209 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -469,6 +469,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
*/
private void extractColors(WallpaperData wallpaper) {
String cropFile = null;
+ boolean defaultImageWallpaper = false;
int wallpaperId;
if (wallpaper.equals(mFallbackWallpaper)) {
@@ -482,6 +483,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
|| wallpaper.wallpaperComponent == null;
if (imageWallpaper && wallpaper.cropFile != null && wallpaper.cropFile.exists()) {
cropFile = wallpaper.cropFile.getAbsolutePath();
+ } else if (imageWallpaper && !wallpaper.cropExists() && !wallpaper.sourceExists()) {
+ defaultImageWallpaper = true;
}
wallpaperId = wallpaper.wallpaperId;
}
@@ -493,6 +496,25 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
colors = WallpaperColors.fromBitmap(bitmap);
bitmap.recycle();
}
+ } else if (defaultImageWallpaper) {
+ // There is no crop and source file because this is default image wallpaper.
+ try (final InputStream is =
+ WallpaperManager.openDefaultWallpaper(mContext, FLAG_SYSTEM)) {
+ if (is != null) {
+ try {
+ final BitmapFactory.Options options = new BitmapFactory.Options();
+ final Bitmap bitmap = BitmapFactory.decodeStream(is, null, options);
+ if (bitmap != null) {
+ colors = WallpaperColors.fromBitmap(bitmap);
+ bitmap.recycle();
+ }
+ } catch (OutOfMemoryError e) {
+ Slog.w(TAG, "Can't decode default wallpaper stream", e);
+ }
+ }
+ } catch (IOException e) {
+ Slog.w(TAG, "Can't close default wallpaper stream", e);
+ }
}
if (colors == null) {
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 65d66f44b5dd..e817dd47e756 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -558,22 +558,26 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
}
/**
- * Pause all activities in either all of the stacks or just the back stacks.
+ * Pause all activities in either all of the stacks or just the back stacks. This is done before
+ * resuming a new activity and to make sure that previously active activities are
+ * paused in stacks that are no longer visible or in pinned windowing mode. This does not
+ * pause activities in visible stacks, so if an activity is launched within the same stack/task,
+ * then we should explicitly pause that stack's top activity.
* @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
* @param resuming The resuming activity.
* @param dontWait The resuming activity isn't going to wait for all activities to be paused
* before resuming.
- * @return true if any activity was paused as a result of this call.
+ * @return {@code true} if any activity was paused as a result of this call.
*/
boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming, boolean dontWait) {
boolean someActivityPaused = false;
for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = mStacks.get(stackNdx);
- // TODO(b/111541062): Check if resumed activity on this display instead
- if (!mRootActivityContainer.isTopDisplayFocusedStack(stack)
- && stack.getResumedActivity() != null) {
+ final ActivityRecord resumedActivity = stack.getResumedActivity();
+ if (resumedActivity != null
+ && (!stack.shouldBeVisible(resuming) || !stack.isFocusable())) {
if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack +
- " mResumedActivity=" + stack.getResumedActivity());
+ " mResumedActivity=" + resumedActivity);
someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
dontWait);
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b8634d88319a..b7c35c083174 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1946,30 +1946,90 @@ final class ActivityRecord extends ConfigurationContainer {
try {
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
WindowVisibilityItem.obtain(true /* showWindow */));
- if (shouldPauseWhenBecomingVisible()) {
- // An activity must be in the {@link PAUSING} state for the system to validate
- // the move to {@link PAUSED}.
- setState(PAUSING, "makeVisibleIfNeeded");
+ makeActiveIfNeeded(null /* activeActivity*/);
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception thrown sending visibility update: " + intent.getComponent(), e);
+ }
+ }
+
+ /**
+ * Make activity resumed or paused if needed.
+ * @param activeActivity an activity that is resumed or just completed pause action.
+ * We won't change the state of this activity.
+ */
+ boolean makeActiveIfNeeded(ActivityRecord activeActivity) {
+ if (shouldResumeActivity(activeActivity)) {
+ if (DEBUG_VISIBILITY) {
+ Slog.v("TAG_VISIBILITY", "Resume visible activity, " + this);
+ }
+ return getActivityStack().resumeTopActivityUncheckedLocked(activeActivity /* prev */,
+ null /* options */);
+ } else if (shouldPauseActivity(activeActivity)) {
+ if (DEBUG_VISIBILITY) {
+ Slog.v("TAG_VISIBILITY", "Pause visible activity, " + this);
+ }
+ // An activity must be in the {@link PAUSING} state for the system to validate
+ // the move to {@link PAUSED}.
+ setState(PAUSING, "makeVisibleIfNeeded");
+ try {
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
PauseActivityItem.obtain(finishing, false /* userLeaving */,
configChangeFlags, false /* dontReport */));
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e);
}
- } catch (Exception e) {
- Slog.w(TAG, "Exception thrown sending visibility update: " + intent.getComponent(), e);
}
+ return false;
}
- /** Check if activity should be moved to PAUSED state when it becomes visible. */
- private boolean shouldPauseWhenBecomingVisible() {
- // If the activity is stopped or stopping, cycle to the paused state. We avoid doing
+ /**
+ * Check if activity should be moved to PAUSED state. The activity:
+ * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)})
+ * - should be non-focusable
+ * - should not be currently pausing or paused
+ * @param activeActivity the activity that is active or just completed pause action. We won't
+ * resume if this activity is active.
+ */
+ private boolean shouldPauseActivity(ActivityRecord activeActivity) {
+ return shouldMakeActive(activeActivity) && !isFocusable() && !isState(PAUSING, PAUSED);
+ }
+
+ /**
+ * Check if activity should be moved to RESUMED state. The activity:
+ * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)})
+ * - should be focusable
+ * @param activeActivity the activity that is active or just completed pause action. We won't
+ * resume if this activity is active.
+ */
+ private boolean shouldResumeActivity(ActivityRecord activeActivity) {
+ return shouldMakeActive(activeActivity) && isFocusable() && !isState(RESUMED);
+ }
+
+ /**
+ * Check if activity is eligible to be made active (resumed of paused). The activity:
+ * - should be paused, stopped or stopping
+ * - should not be the currently active one or launching behind other tasks
+ * - should be either the topmost in task, or right below the top activity that is finishing
+ * If all of these conditions are not met at the same time, the activity cannot be made active.
+ */
+ private boolean shouldMakeActive(ActivityRecord activeActivity) {
+ // If the activity is stopped, stopping, cycle to an active state. We avoid doing
// this when there is an activity waiting to become translucent as the extra binder
// calls will lead to noticeable jank. A later call to
- // ActivityStack#ensureActivitiesVisibleLocked will bring the activity to the proper
- // paused state. We also avoid doing this for the activity the stack supervisor
- // considers the resumed activity, as normal means will bring the activity from STOPPED
- // to RESUMED. Adding PAUSING in this scenario will lead to double lifecycles.
- if (!isState(STOPPED, STOPPING) || getActivityStack().mTranslucentActivityWaiting != null
- || isResumedActivityOnDisplay()) {
+ // ActivityStack#ensureActivitiesVisibleLocked will bring the activity to a proper
+ // active state.
+ if (!isState(RESUMED, PAUSED, STOPPED, STOPPING)
+ || getActivityStack().mTranslucentActivityWaiting != null) {
+ return false;
+ }
+
+ if (this == activeActivity) {
+ return false;
+ }
+
+ if (this.mLaunchTaskBehind) {
+ // This activity is being launched from behind, which means that it's not intended to be
+ // presented to user right now, even if it's set to be visible.
return false;
}
@@ -1979,14 +2039,14 @@ final class ActivityRecord extends ConfigurationContainer {
throw new IllegalStateException("Activity not found in its task");
}
if (positionInTask == task.mActivities.size() - 1) {
- // It's the topmost activity in the task - should become paused now
+ // It's the topmost activity in the task - should become resumed now
return true;
}
// Check if activity above is finishing now and this one becomes the topmost in task.
final ActivityRecord activityAbove = task.mActivities.get(positionInTask + 1);
if (activityAbove.finishing && results == null) {
- // We will only allow pausing if activity above wasn't launched for result. Otherwise it
- // will cause this activity to resume before getting result.
+ // We will only allow making active if activity above wasn't launched for result.
+ // Otherwise it will cause this activity to resume before getting result.
return true;
}
return false;
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 3a754c411684..c97e4e8a9bc0 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -357,6 +357,11 @@ class ActivityStack extends ConfigurationContainer {
*/
boolean mForceHidden = false;
+ /**
+ * Used to keep resumeTopActivityUncheckedLocked() from being entered recursively
+ */
+ boolean mInResumeTopActivity = false;
+
private boolean mUpdateBoundsDeferred;
private boolean mUpdateBoundsDeferredCalled;
private boolean mUpdateDisplayedBoundsDeferredCalled;
@@ -1732,6 +1737,7 @@ class ActivityStack extends ConfigurationContainer {
"Activity paused: token=" + token + ", timeout=" + timeout);
final ActivityRecord r = isInStackLocked(token);
+
if (r != null) {
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
if (mPausingActivity == r) {
@@ -2088,8 +2094,7 @@ class ActivityStack extends ConfigurationContainer {
boolean aboveTop = top != null;
final boolean stackShouldBeVisible = shouldBeVisible(starting);
boolean behindFullscreenActivity = !stackShouldBeVisible;
- boolean resumeNextActivity = mRootActivityContainer.isTopDisplayFocusedStack(this)
- && (isInStackLocked(starting) == null);
+ boolean resumeNextActivity = isFocusable() && isInStackLocked(starting) == null;
final boolean isTopNotPinnedStack =
isAttached() && getDisplay().isTopNotPinnedStack(this);
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -2150,6 +2155,10 @@ class ActivityStack extends ConfigurationContainer {
if (r.handleAlreadyVisible()) {
resumeNextActivity = false;
}
+
+ if (notifyClients) {
+ r.makeActiveIfNeeded(starting);
+ }
} else {
r.makeVisibleIfNeeded(starting, notifyClients);
}
@@ -2327,7 +2336,7 @@ class ActivityStack extends ConfigurationContainer {
r.setVisible(true);
}
if (r != starting) {
- mStackSupervisor.startSpecificActivityLocked(r, andResume, false);
+ mStackSupervisor.startSpecificActivityLocked(r, andResume, true /* checkConfig */);
return true;
}
}
@@ -2505,7 +2514,7 @@ class ActivityStack extends ConfigurationContainer {
*/
@GuardedBy("mService")
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
- if (mStackSupervisor.inResumeTopActivity) {
+ if (mInResumeTopActivity) {
// Don't even start recursing.
return false;
}
@@ -2513,7 +2522,7 @@ class ActivityStack extends ConfigurationContainer {
boolean result = false;
try {
// Protect against recursion.
- mStackSupervisor.inResumeTopActivity = true;
+ mInResumeTopActivity = true;
result = resumeTopActivityInnerLocked(prev, options);
// When resuming the top activity, it may be necessary to pause the top activity (for
@@ -2528,7 +2537,7 @@ class ActivityStack extends ConfigurationContainer {
checkReadyForSleep();
}
} finally {
- mStackSupervisor.inResumeTopActivity = false;
+ mInResumeTopActivity = false;
}
return result;
@@ -2561,7 +2570,7 @@ class ActivityStack extends ConfigurationContainer {
// Find the next top-most activity to resume in this stack that is not finishing and is
// focusable. If it is not focusable, we will fall into the case below to resume the
// top activity in the next focusable task.
- final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
+ ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
final boolean hasRunningActivity = next != null;
@@ -2649,6 +2658,12 @@ class ActivityStack extends ConfigurationContainer {
if (!mRootActivityContainer.allPausedActivitiesComplete()) {
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
"resumeTopActivityLocked: Skip resume: some activity pausing.");
+
+ // Adding previous activity to the waiting visible list, or it would be stopped
+ // before top activity being visible.
+ if (prev != null && !next.nowVisible) {
+ mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(prev);
+ }
return false;
}
@@ -2858,7 +2873,9 @@ class ActivityStack extends ConfigurationContainer {
// the screen based on the new activity order.
boolean notUpdated = true;
- if (isFocusedStackOnDisplay()) {
+ // Activity should also be visible if set mLaunchTaskBehind to true (see
+ // ActivityRecord#shouldBeVisibleIgnoringKeyguard()).
+ if (shouldBeVisible(next)) {
// We have special rotation behavior when here is some active activity that
// requests specific orientation or Keyguard is locked. Make sure all activity
// visibilities are set correctly as well as the transition is updated if needed
@@ -4087,6 +4104,12 @@ class ActivityStack extends ConfigurationContainer {
mStackSupervisor.mFinishingActivities.add(r);
r.resumeKeyDispatchingLocked();
mRootActivityContainer.resumeFocusedStacksTopActivities();
+ // If activity was not paused at this point - explicitly pause it to start finishing
+ // process. Finishing will be completed once it reports pause back.
+ if (r.isState(RESUMED) && mPausingActivity != null) {
+ startPausingLocked(false /* userLeaving */, false /* uiSleeping */, next /* resuming */,
+ false /* dontWait */);
+ }
return r;
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 3a288ca5560d..a83ef34f1cac 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -327,9 +327,6 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
*/
PowerManager.WakeLock mGoingToSleep;
- /** Used to keep resumeTopActivityUncheckedLocked() from being entered recursively */
- boolean inResumeTopActivity;
-
/**
* Temporary rect used during docked stack resize calculation so we don't need to create a new
* object each time.
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 280709461c98..43c12064a3c1 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -179,7 +179,10 @@ public class ActivityStartController {
.setActivityOptions(options.toBundle())
.execute();
mLastHomeActivityStartRecord = tmpOutRecord[0];
- if (mSupervisor.inResumeTopActivity) {
+ final ActivityDisplay display =
+ mService.mRootActivityContainer.getActivityDisplay(displayId);
+ final ActivityStack homeStack = display != null ? display.getHomeStack() : null;
+ if (homeStack != null && homeStack.mInResumeTopActivity) {
// If we are in resume section already, home activity will be initialized, but not
// resumed (to avoid recursive resume) and will stay that way until something pokes it
// again. We need to schedule another resume.
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 38580bc41f74..b0e581134a95 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -982,7 +982,8 @@ class ActivityStarter {
/** Returns true if uid is in a persistent state. */
private boolean isUidPersistentSystemProcess(int uid) {
- return (mService.getUidStateLocked(uid) <= ActivityManager.PROCESS_STATE_PERSISTENT_UI);
+ return (uid == Process.SYSTEM_UID)
+ || (mService.getUidStateLocked(uid) <= ActivityManager.PROCESS_STATE_PERSISTENT_UI);
}
private void maybeLogActivityStart(int callingUid, String callingPackage, int realCallingUid,
@@ -1632,7 +1633,7 @@ class ActivityStarter {
// Also, we don't want to resume activities in a task that currently has an overlay
// as the starting activity just needs to be in the visible paused state until the
// over is removed.
- mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+ mTargetStack.ensureActivitiesVisibleLocked(mStartActivity, 0, !PRESERVE_WINDOWS);
// Go ahead and tell window manager to execute app transition for this activity
// since the app transition will not be triggered through the resume channel.
mTargetStack.getDisplay().mDisplayContent.executeAppTransition();
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 40063326e76e..bbf115f17969 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2574,6 +2574,10 @@ public class DisplayPolicy {
}
}
+ void notifyDisplayReady() {
+ mHandler.post(() -> getStatusBarManagerInternal().onDisplayReady(getDisplayId()));
+ }
+
/**
* Return the display width available after excluding any screen
* decorations that could never be removed in Honeycomb. That is, system bar or
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 9b7214120aed..e95ac5c43315 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -1108,28 +1108,41 @@ class RootActivityContainer extends ConfigurationContainer
return false;
}
+ boolean result = false;
if (targetStack != null && (targetStack.isTopStackOnDisplay()
|| getTopDisplayFocusedStack() == targetStack)) {
- return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
+ result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
- // Resume all top activities in focused stacks on all displays.
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+ boolean resumedOnDisplay = false;
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- final ActivityStack focusedStack = display.getFocusedStack();
- if (focusedStack == null) {
- continue;
+ for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
+ final ActivityStack stack = display.getChildAt(stackNdx);
+ final ActivityRecord topRunningActivity = stack.topRunningActivityLocked();
+ if (!stack.isFocusableAndVisible() || topRunningActivity == null) {
+ continue;
+ }
+ if (topRunningActivity.isState(RESUMED)) {
+ // Kick off any lingering app transitions form the MoveTaskToFront operation.
+ stack.executeAppTransition(targetOptions);
+ } else {
+ resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target);
+ }
}
- final ActivityRecord r = focusedStack.topRunningActivityLocked();
- if (r == null || !r.isState(RESUMED)) {
- focusedStack.resumeTopActivityUncheckedLocked(null, null);
- } else if (r.isState(RESUMED)) {
- // Kick off any lingering app transitions form the MoveTaskToFront operation.
- focusedStack.executeAppTransition(targetOptions);
+ if (!resumedOnDisplay) {
+ // In cases when there are no valid activities (e.g. device just booted or launcher
+ // crashed) it's possible that nothing was resumed on a display. Requesting resume
+ // of top activity in focused stack explicitly will make sure that at least home
+ // activity is started and resumed, and no recursion occurs.
+ final ActivityStack focusedStack = display.getFocusedStack();
+ if (focusedStack != null) {
+ focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
+ }
}
}
- return false;
+ return result;
}
void applySleepTokens(boolean applyToStacks) {
@@ -1283,16 +1296,21 @@ class RootActivityContainer extends ConfigurationContainer
public void onDisplayAdded(int displayId) {
if (DEBUG_STACK) Slog.v(TAG, "Display added displayId=" + displayId);
synchronized (mService.mGlobalLock) {
- getActivityDisplayOrCreate(displayId);
+ final ActivityDisplay display = getActivityDisplayOrCreate(displayId);
// Do not start home before booting, or it may accidentally finish booting before it
// starts. Instead, we expect home activities to be launched when the system is ready
// (ActivityManagerService#systemReady).
if (mService.isBooted() || mService.isBooting()) {
- startHomeOnDisplay(mCurrentUser, "displayAdded", displayId);
+ startSystemDecorations(display.mDisplayContent);
}
}
}
+ private void startSystemDecorations(final DisplayContent displayContent) {
+ startHomeOnDisplay(mCurrentUser, "displayAdded", displayContent.getDisplayId());
+ displayContent.getDisplayPolicy().notifyDisplayReady();
+ }
+
@Override
public void onDisplayRemoved(int displayId) {
if (DEBUG_STACK) Slog.v(TAG, "Display removed displayId=" + displayId);
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index 69dcaf473b12..0529ed128130 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -698,6 +698,14 @@ class TaskRecord extends ConfigurationContainer {
return false;
}
+ final boolean toTopOfStack = position == MAX_VALUE;
+ if (toTopOfStack && toStack.getResumedActivity() != null
+ && toStack.topRunningActivityLocked() != null) {
+ // Pause the resumed activity on the target stack while re-parenting task on top of it.
+ toStack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */,
+ null /* resuming */, false /* pauseImmediately */);
+ }
+
final int toStackWindowingMode = toStack.getWindowingMode();
final ActivityRecord topActivity = getTopActivity();
diff --git a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
index e99dd4f1cbae..bbecc6359a40 100644
--- a/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
+++ b/services/ipmemorystore/java/com/android/server/net/ipmemorystore/IpMemoryStoreDatabase.java
@@ -16,6 +16,9 @@
package com.android.server.net.ipmemorystore;
+import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
+import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentValues;
@@ -27,7 +30,6 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQuery;
-import android.net.NetworkUtils;
import android.net.ipmemorystore.NetworkAttributes;
import android.net.ipmemorystore.Status;
import android.util.Log;
@@ -200,7 +202,7 @@ public class IpMemoryStoreDatabase {
if (null == attributes) return values;
if (null != attributes.assignedV4Address) {
values.put(NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESS,
- NetworkUtils.inet4AddressToIntHTH(attributes.assignedV4Address));
+ inet4AddressToIntHTH(attributes.assignedV4Address));
}
if (null != attributes.groupHint) {
values.put(NetworkAttributesContract.COLNAME_GROUPHINT, attributes.groupHint);
@@ -254,7 +256,7 @@ public class IpMemoryStoreDatabase {
getBlob(cursor, NetworkAttributesContract.COLNAME_DNSADDRESSES);
final int mtu = getInt(cursor, NetworkAttributesContract.COLNAME_MTU, -1);
if (0 != assignedV4AddressInt) {
- builder.setAssignedV4Address(NetworkUtils.intToInet4AddressHTH(assignedV4AddressInt));
+ builder.setAssignedV4Address(intToInet4AddressHTH(assignedV4AddressInt));
}
builder.setGroupHint(groupHint);
if (null != dnsAddressesBlob) {
diff --git a/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java b/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java
index f068c3ac16e2..1fe2328f1cdb 100644
--- a/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java
+++ b/services/net/java/android/net/dhcp/DhcpServingParamsParcelExt.java
@@ -16,7 +16,7 @@
package android.net.dhcp;
-import static android.net.NetworkUtils.inet4AddressToIntHTH;
+import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
import android.annotation.NonNull;
import android.net.LinkAddress;
diff --git a/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java b/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
index 2c368c81523e..00073503886a 100644
--- a/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
+++ b/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java
@@ -73,7 +73,7 @@ public final class IpConfigurationParcelableUtil {
public static DhcpResultsParcelable toStableParcelable(@Nullable DhcpResults results) {
if (results == null) return null;
final DhcpResultsParcelable p = new DhcpResultsParcelable();
- p.baseConfiguration = toStableParcelable((StaticIpConfiguration) results);
+ p.baseConfiguration = toStableParcelable(results.toStaticIpConfiguration());
p.leaseDuration = results.leaseDuration;
p.mtu = results.mtu;
p.serverAddress = parcelAddress(results.serverAddress);
diff --git a/services/net/java/android/net/shared/NetdService.java b/services/net/java/android/net/shared/NetdService.java
index be0f5f2d4f34..f5ae72587294 100644
--- a/services/net/java/android/net/shared/NetdService.java
+++ b/services/net/java/android/net/shared/NetdService.java
@@ -16,6 +16,7 @@
package android.net.shared;
+import android.content.Context;
import android.net.INetd;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -28,7 +29,6 @@ import android.util.Log;
*/
public class NetdService {
private static final String TAG = NetdService.class.getSimpleName();
- private static final String NETD_SERVICE_NAME = "netd";
private static final long BASE_TIMEOUT_MS = 100;
private static final long MAX_TIMEOUT_MS = 1000;
@@ -48,7 +48,7 @@ public class NetdService {
// NOTE: ServiceManager does no caching for the netd service,
// because netd is not one of the defined common services.
final INetd netdInstance = INetd.Stub.asInterface(
- ServiceManager.getService(NETD_SERVICE_NAME));
+ ServiceManager.getService(Context.NETD_SERVICE));
if (netdInstance == null) {
Log.w(TAG, "WARNING: returning null INetd instance.");
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
index 410ab8732a08..e658d179f4f3 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAdjustmentExtractorTest.java
@@ -59,7 +59,7 @@ public class NotificationAdjustmentExtractorTest extends UiServiceTestCase {
signals.putStringArrayList(Adjustment.KEY_PEOPLE, people);
ArrayList<Notification.Action> smartActions = new ArrayList<>();
smartActions.add(createAction());
- signals.putParcelableArrayList(Adjustment.KEY_SMART_ACTIONS, smartActions);
+ signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, smartActions);
Adjustment adjustment = new Adjustment("pkg", r.getKey(), signals, "", 0);
r.addAdjustment(adjustment);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 62229235a026..9c6ab0ab9aa9 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -3410,6 +3410,77 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast() {
+ // Post 2 notifications from 2 packages
+ NotificationRecord pkgA = new NotificationRecord(mContext,
+ generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgA);
+ NotificationRecord pkgB = new NotificationRecord(mContext,
+ generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgB);
+
+ // on broadcast, hide one of the packages
+ mService.simulatePackageDistractionBroadcast(
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a"});
+ ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class);
+ verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture());
+ assertEquals(1, captorHide.getValue().size());
+ assertEquals("a", captorHide.getValue().get(0).sbn.getPackageName());
+
+ // on broadcast, unhide the package
+ mService.simulatePackageDistractionBroadcast(
+ PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a"});
+ ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class);
+ verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture());
+ assertEquals(1, captorUnhide.getValue().size());
+ assertEquals("a", captorUnhide.getValue().get(0).sbn.getPackageName());
+ }
+
+ @Test
+ public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast_multiPkg() {
+ // Post 2 notifications from 2 packages
+ NotificationRecord pkgA = new NotificationRecord(mContext,
+ generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgA);
+ NotificationRecord pkgB = new NotificationRecord(mContext,
+ generateSbn("b", 1001, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgB);
+
+ // on broadcast, hide one of the packages
+ mService.simulatePackageDistractionBroadcast(
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a", "b"});
+ ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class);
+ verify(mListeners, times(2)).notifyHiddenLocked(captorHide.capture());
+ assertEquals(2, captorHide.getValue().size());
+ assertEquals("a", captorHide.getValue().get(0).sbn.getPackageName());
+ assertEquals("b", captorHide.getValue().get(1).sbn.getPackageName());
+
+ // on broadcast, unhide the package
+ mService.simulatePackageDistractionBroadcast(
+ PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a", "b"});
+ ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class);
+ verify(mListeners, times(2)).notifyUnhiddenLocked(captorUnhide.capture());
+ assertEquals(2, captorUnhide.getValue().size());
+ assertEquals("a", captorUnhide.getValue().get(0).sbn.getPackageName());
+ assertEquals("b", captorUnhide.getValue().get(1).sbn.getPackageName());
+ }
+
+ @Test
+ public void testNoNotificationsHiddenOnDistractingPackageBroadcast() {
+ // post notification from this package
+ final NotificationRecord notif1 = generateNotificationRecord(
+ mTestNotificationChannel, 1, null, true);
+ mService.addNotification(notif1);
+
+ // on broadcast, nothing is hidden since no notifications are of package "test_package"
+ mService.simulatePackageDistractionBroadcast(
+ PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"test_package"});
+ ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
+ verify(mListeners, times(1)).notifyHiddenLocked(captor.capture());
+ assertEquals(0, captor.getValue().size());
+ }
+
+ @Test
public void testCanUseManagedServicesLowRamNoWatchNullPkg() {
when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
when(mActivityManager.isLowRamDevice()).thenReturn(true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 8be63fc43adb..319ffed3778c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -31,6 +31,7 @@ import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
+import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
@@ -75,6 +76,9 @@ public class ActivityRecordTests extends ActivityTestsBase {
mStack = (TestActivityStack) new StackBuilder(mRootActivityContainer).build();
mTask = mStack.getChildAt(0);
mActivity = mTask.getTopActivity();
+
+ doReturn(false).when(mService).isBooting();
+ doReturn(true).when(mService).isBooted();
}
@Test
@@ -117,22 +121,23 @@ public class ActivityRecordTests extends ActivityTestsBase {
mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
- // The activity is in the focused stack so it should not move to paused.
+ // The activity is in the focused stack so it should be resumed.
mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
- assertTrue(mActivity.isState(STOPPED));
+ assertTrue(mActivity.isState(RESUMED));
assertFalse(pauseFound.value);
- // Clear focused stack
- final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
- when(display.getFocusedStack()).thenReturn(null);
+ // Make the activity non focusable
+ mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped");
+ doReturn(false).when(mActivity).isFocusable();
- // In the unfocused stack, the activity should move to paused.
+ // If the activity is not focusable, it should move to paused.
mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
assertTrue(mActivity.isState(PAUSING));
assertTrue(pauseFound.value);
// Make sure that the state does not change for current non-stopping states.
mActivity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped");
+ doReturn(true).when(mActivity).isFocusable();
mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index 68df87e3e27d..ea8f33f0c630 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -55,6 +55,7 @@ import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Handler;
import android.os.Looper;
+import android.os.PowerManager;
import android.os.Process;
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionSession;
@@ -425,6 +426,7 @@ class ActivityTestsBase {
doReturn(mock(IPackageManager.class)).when(this).getPackageManager();
// allow background activity starts by default
doReturn(true).when(this).isBackgroundActivityStartsEnabled();
+ doNothing().when(this).updateCpuStats();
}
void setup(IntentFirewall intentFirewall, PendingIntentController intentController,
@@ -580,6 +582,8 @@ class ActivityTestsBase {
doNothing().when(this).acquireLaunchWakelock();
doReturn(mKeyguardController).when(this).getKeyguardController();
+ mLaunchingActivity = mock(PowerManager.WakeLock.class);
+
initialize();
}
diff --git a/telephony/java/android/telephony/IFinancialSmsCallback.aidl b/telephony/java/android/telephony/IFinancialSmsCallback.aidl
new file mode 100644
index 000000000000..aa88615c15cf
--- /dev/null
+++ b/telephony/java/android/telephony/IFinancialSmsCallback.aidl
@@ -0,0 +1,34 @@
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+package android.telephony;
+
+import android.app.PendingIntent;
+import android.database.CursorWindow;
+import android.net.Uri;
+import android.os.Bundle;
+import com.android.internal.telephony.SmsRawData;
+
+/** Interface for returning back the financial sms messages asynchrously.
+ * @hide
+ */
+interface IFinancialSmsCallback {
+ /**
+ * Return sms messages back to calling financial app.
+ *
+ * @param messages the sms messages returned for cinancial app.
+ */
+ oneway void onGetSmsMessagesForFinancialApp(in CursorWindow messages);
+}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index d777bf123b67..fae7920d1ab8 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -16,6 +16,9 @@
package android.telephony;
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SuppressAutoDoc;
import android.annotation.SystemApi;
@@ -30,8 +33,10 @@ import android.content.ActivityNotFoundException;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
+import android.database.CursorWindow;
import android.net.Uri;
import android.os.BaseBundle;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
@@ -49,6 +54,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Executor;
/*
* TODO(code review): Curious question... Why are a lot of these
@@ -2144,6 +2150,116 @@ public final class SmsManager {
}
}
+ /** callback for providing asynchronous sms messages for financial app. */
+ public abstract static class FinancialSmsCallback {
+ /**
+ * Callback to send sms messages back to financial app asynchronously.
+ *
+ * @param msgs SMS messages.
+ */
+ public abstract void onFinancialSmsMessages(CursorWindow msgs);
+ };
+
+ /**
+ * Get SMS messages for the calling financial app.
+ * The result will be delivered asynchronously in the passing in callback interface.
+ *
+ * @param params the parameters to filter SMS messages returned.
+ * @param executor the executor on which callback will be invoked.
+ * @param callback a callback to receive CursorWindow with SMS messages.
+ */
+ @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS)
+ public void getSmsMessagesForFinancialApp(
+ Bundle params,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull FinancialSmsCallback callback) {
+ try {
+ ISms iccSms = getISmsServiceOrThrow();
+ iccSms.getSmsMessagesForFinancialApp(
+ getSubscriptionId(), ActivityThread.currentPackageName(), params,
+ new IFinancialSmsCallback.Stub() {
+ public void onGetSmsMessagesForFinancialApp(CursorWindow msgs) {
+ Binder.withCleanCallingIdentity(() -> executor.execute(
+ () -> callback.onFinancialSmsMessages(msgs)));
+ }});
+ } catch (RemoteException ex) {
+ ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @see #createAppSpecificSmsTokenWithPackageInfo().
+ * The prefixes is a list of prefix {@code String} separated by this delimiter.
+ * @hide
+ */
+ public static final String REGEX_PREFIX_DELIMITER = ",";
+ /**
+ * @see #createAppSpecificSmsTokenWithPackageInfo().
+ * The success status to be added into the intent to be sent to the calling package.
+ * @hide
+ */
+ public static final int RESULT_STATUS_SUCCESS = 0;
+ /**
+ * @see #createAppSpecificSmsTokenWithPackageInfo().
+ * The timeout status to be added into the intent to be sent to the calling package.
+ * @hide
+ */
+ public static final int RESULT_STATUS_TIMEOUT = 1;
+ /**
+ * @see #createAppSpecificSmsTokenWithPackageInfo().
+ * Intent extra key of the retrieved SMS message as a {@code String}.
+ * @hide
+ */
+ public static final String EXTRA_SMS_MESSAGE = "android.telephony.extra.SMS_MESSAGE";
+ /**
+ * @see #createAppSpecificSmsTokenWithPackageInfo().
+ * Intent extra key of SMS retriever status, which indicates whether the request for the
+ * coming SMS message is SUCCESS or TIMEOUT
+ * @hide
+ */
+ public static final String EXTRA_STATUS = "android.telephony.extra.STATUS";
+ /**
+ * @see #createAppSpecificSmsTokenWithPackageInfo().
+ * [Optional] Intent extra key of the retrieved Sim card subscription Id if any. {@code int}
+ * @hide
+ */
+ public static final String EXTRA_SIM_SUBSCRIPTION_ID =
+ "android.telephony.extra.SIM_SUBSCRIPTION_ID";
+
+ /**
+ * Create a single use app specific incoming SMS request for the calling package.
+ *
+ * This method returns a token that if included in a subsequent incoming SMS message, and the
+ * SMS message has a prefix from the given prefixes list, the provided {@code intent} will be
+ * sent with the SMS data to the calling package.
+ *
+ * The token is only good for one use within a reasonable amount of time. After an SMS has been
+ * received containing the token all subsequent SMS messages with the token will be routed as
+ * normal.
+ *
+ * An app can only have one request at a time, if the app already has a request pending it will
+ * be replaced with a new request.
+ *
+ * @param prefixes this is a list of prefixes string separated by REGEX_PREFIX_DELIMITER. The
+ * matching SMS message should have at least one of the prefixes in the beginning of the
+ * message.
+ * @param intent this intent is sent when the matching SMS message is received.
+ * @return Token to include in an SMS message.
+ */
+ @Nullable
+ public String createAppSpecificSmsTokenWithPackageInfo(
+ @Nullable String prefixes, @NonNull PendingIntent intent) {
+ try {
+ ISms iccSms = getISmsServiceOrThrow();
+ return iccSms.createAppSpecificSmsTokenWithPackageInfo(getSubscriptionId(),
+ ActivityThread.currentPackageName(), prefixes, intent);
+
+ } catch (RemoteException ex) {
+ ex.rethrowFromSystemServer();
+ return null;
+ }
+ }
+
/**
* Filters a bundle to only contain MMS config variables.
*
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index e710e0e02c46..98fc7251e9a8 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -6848,13 +6848,13 @@ public class TelephonyManager {
/**
* Values used to return status for hasCarrierPrivileges call.
*/
- /** @hide */ @SystemApi
+ /** @hide */ @SystemApi @TestApi
public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1;
- /** @hide */ @SystemApi
+ /** @hide */ @SystemApi @TestApi
public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0;
- /** @hide */ @SystemApi
+ /** @hide */ @SystemApi @TestApi
public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1;
- /** @hide */ @SystemApi
+ /** @hide */ @SystemApi @TestApi
public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2;
/**
@@ -7056,6 +7056,7 @@ public class TelephonyManager {
/** @hide */
@SystemApi
+ @TestApi
@SuppressLint("Doclava125")
public int checkCarrierPrivilegesForPackage(String pkgName) {
try {
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index a4eb424ab66e..b51eda3f1b34 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -18,6 +18,8 @@ package com.android.internal.telephony;
import android.app.PendingIntent;
import android.net.Uri;
+import android.os.Bundle;
+import android.telephony.IFinancialSmsCallback;
import com.android.internal.telephony.SmsRawData;
/** Interface for applications to access the ICC phone book.
@@ -560,4 +562,30 @@ interface ISms {
* @param intent PendingIntent to be sent when an SMS is received containing the token.
*/
String createAppSpecificSmsToken(int subId, String callingPkg, in PendingIntent intent);
+
+ /**
+ * Create an app-only incoming SMS request for the calling package.
+ *
+ * If an incoming text contains the token returned by this method the provided
+ * <code>PendingIntent</code> will be sent containing the SMS data.
+ *
+ * @param subId the SIM id.
+ * @param callingPkg the package name of the calling app.
+ * @param prefixes the caller provided prefixes
+ * @param intent PendingIntent to be sent when a SMS is received containing the token and one
+ * of the prefixes
+ */
+ String createAppSpecificSmsTokenWithPackageInfo(
+ int subId, String callingPkg, String prefixes, in PendingIntent intent);
+
+ /**
+ * Get sms inbox messages for the calling financial app.
+ *
+ * @param subId the SIM id.
+ * @param callingPkg the package name of the calling app.
+ * @param params parameters to filter the sms messages.
+ * @param callback the callback interface to deliver the result.
+ */
+ void getSmsMessagesForFinancialApp(
+ int subId, String callingPkg, in Bundle params, in IFinancialSmsCallback callback);
}
diff --git a/telephony/java/com/android/internal/telephony/ISmsImplBase.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
index 1cdf44d897b2..12c5c308739a 100644
--- a/telephony/java/com/android/internal/telephony/ISmsImplBase.java
+++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
@@ -18,6 +18,8 @@ package com.android.internal.telephony;
import android.app.PendingIntent;
import android.net.Uri;
+import android.os.Bundle;
+import android.telephony.IFinancialSmsCallback;
import java.util.List;
@@ -188,4 +190,16 @@ public class ISmsImplBase extends ISms.Stub {
public String createAppSpecificSmsToken(int subId, String callingPkg, PendingIntent intent) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public String createAppSpecificSmsTokenWithPackageInfo(
+ int subId, String callingPkg, String prefixes, PendingIntent intent) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void getSmsMessagesForFinancialApp(
+ int subId, String callingPkg, Bundle params, IFinancialSmsCallback callback) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/test-mock/src/android/test/mock/MockCursor.java b/test-mock/src/android/test/mock/MockCursor.java
index 576f24ad6384..f69db2c84111 100644
--- a/test-mock/src/android/test/mock/MockCursor.java
+++ b/test-mock/src/android/test/mock/MockCursor.java
@@ -24,6 +24,8 @@ import android.database.DataSetObserver;
import android.net.Uri;
import android.os.Bundle;
+import java.util.List;
+
/**
* A mock {@link android.database.Cursor} class that isolates the test code from real
* Cursor implementation.
@@ -226,11 +228,21 @@ public class MockCursor implements Cursor {
}
@Override
+ public void setNotificationUris(ContentResolver cr, List<Uri> uris) {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
+ @Override
public Uri getNotificationUri() {
throw new UnsupportedOperationException("unimplemented mock method");
}
@Override
+ public List<Uri> getNotificationUris() {
+ throw new UnsupportedOperationException("unimplemented mock method");
+ }
+
+ @Override
public void unregisterContentObserver(ContentObserver observer) {
throw new UnsupportedOperationException("unimplemented mock method");
}
diff --git a/tests/DexLoggerIntegrationTests/Android.mk b/tests/DexLoggerIntegrationTests/Android.mk
index 979d13ac9405..ee02a72b6819 100644
--- a/tests/DexLoggerIntegrationTests/Android.mk
+++ b/tests/DexLoggerIntegrationTests/Android.mk
@@ -35,7 +35,6 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := DexLoggerNativeTestLibrary
-LOCAL_MULTILIB := first
LOCAL_SRC_FILES := src/cpp/com_android_dcl_Jni.cpp
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE)
@@ -44,8 +43,6 @@ LOCAL_NDK_STL_VARIANT := c++_static
include $(BUILD_SHARED_LIBRARY)
-dexloggertest_so := $(LOCAL_BUILT_MODULE)
-
# And a standalone native executable that we can exec.
include $(CLEAR_VARS)
@@ -73,11 +70,15 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
truth-prebuilt \
+# Include both versions of the .so if we have 2 arch
+LOCAL_MULTILIB := both
+LOCAL_JNI_SHARED_LIBRARIES := \
+ DexLoggerNativeTestLibrary \
+
# This gets us the javalib.jar built by DexLoggerTestLibrary above as well as the various
# native binaries.
LOCAL_JAVA_RESOURCE_FILES := \
$(dexloggertest_jar) \
- $(dexloggertest_so) \
- $(dexloggertest_executable)
+ $(dexloggertest_executable) \
include $(BUILD_PACKAGE)
diff --git a/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java b/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java
index d68769b378b9..e92cc56322eb 100644
--- a/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java
+++ b/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertWithMessage;
import android.app.UiAutomation;
import android.content.Context;
+import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.support.test.InstrumentationRegistry;
@@ -147,7 +148,7 @@ public final class DexLoggerIntegrationTests {
String expectedNameHash =
"996223BAD4B4FE75C57A3DEC61DB9C0B38E0A7AD479FC95F33494F4BC55A0F0E";
String expectedContentHash =
- copyAndHashResource("/DexLoggerNativeTestLibrary.so", privateCopyFile);
+ copyAndHashResource(libraryPath("DexLoggerNativeTestLibrary.so"), privateCopyFile);
System.load(privateCopyFile.toString());
@@ -170,7 +171,7 @@ public final class DexLoggerIntegrationTests {
String expectedNameHash =
"8C39990C560B4F36F83E208E279F678746FE23A790E4C50F92686584EA2041CA";
String expectedContentHash =
- copyAndHashResource("/DexLoggerNativeTestLibrary.so", privateCopyFile);
+ copyAndHashResource(libraryPath("DexLoggerNativeTestLibrary.so"), privateCopyFile);
System.load(privateCopyFile.toString());
@@ -307,6 +308,12 @@ public final class DexLoggerIntegrationTests {
return new File(sContext.getDir("dcl", Context.MODE_PRIVATE), name);
}
+ private String libraryPath(final String libraryName) {
+ // This may be deprecated. but it tells us the ABI of this process which is exactly what we
+ // want.
+ return "/lib/" + Build.CPU_ABI + "/" + libraryName;
+ }
+
private static String copyAndHashResource(String resourcePath, File copyTo) throws Exception {
MessageDigest hasher = MessageDigest.getInstance("SHA-256");
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index ec07037b3a8f..86af6422dad3 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -26,8 +26,8 @@ import android.os.test.TestLooper;
import android.support.test.InstrumentationRegistry;
import com.android.server.PackageWatchdog.PackageHealthObserver;
+import com.android.server.PackageWatchdog.PackageHealthObserverImpact;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -45,23 +45,22 @@ import java.util.concurrent.TimeUnit;
public class PackageWatchdogTest {
private static final String APP_A = "com.package.a";
private static final String APP_B = "com.package.b";
+ private static final String APP_C = "com.package.c";
+ private static final String APP_D = "com.package.d";
private static final String OBSERVER_NAME_1 = "observer1";
private static final String OBSERVER_NAME_2 = "observer2";
private static final String OBSERVER_NAME_3 = "observer3";
+ private static final String OBSERVER_NAME_4 = "observer4";
private static final long SHORT_DURATION = TimeUnit.SECONDS.toMillis(1);
private static final long LONG_DURATION = TimeUnit.SECONDS.toMillis(5);
private TestLooper mTestLooper;
@Before
public void setUp() throws Exception {
- mTestLooper = new TestLooper();
- mTestLooper.startAutoDispatch();
- }
-
- @After
- public void tearDown() throws Exception {
new File(InstrumentationRegistry.getContext().getFilesDir(),
"package-watchdog.xml").delete();
+ mTestLooper = new TestLooper();
+ mTestLooper.startAutoDispatch();
}
/**
@@ -154,7 +153,6 @@ public class PackageWatchdogTest {
assertTrue(watchdog1.getPackages(observer2).contains(APP_A));
assertTrue(watchdog1.getPackages(observer2).contains(APP_B));
-
// Then advance time and run IO Handler so file is saved
mTestLooper.dispatchAll();
@@ -198,47 +196,191 @@ public class PackageWatchdogTest {
watchdog.onPackageFailure(new String[]{APP_A});
}
+ // Run handler so package failures are dispatched to observers
+ mTestLooper.dispatchAll();
+
// Verify that observers are not notified
assertEquals(0, observer1.mFailedPackages.size());
assertEquals(0, observer2.mFailedPackages.size());
}
/**
- * Test package failure and notifies all observer since none handles the failure
+ * Test package failure and does not notify any observer because they are not observing
+ * the failed packages.
*/
@Test
- public void testPackageFailureNotifyAll() throws Exception {
+ public void testPackageFailureNotifyNone() throws Exception {
PackageWatchdog watchdog = createWatchdog();
- TestObserver observer1 = new TestObserver(OBSERVER_NAME_1);
- TestObserver observer2 = new TestObserver(OBSERVER_NAME_2);
+ TestObserver observer1 = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_HIGH);
+ TestObserver observer2 = new TestObserver(OBSERVER_NAME_2,
+ PackageHealthObserverImpact.USER_IMPACT_HIGH);
+
- // Start observing for observer1 and observer2 without handling failures
watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
- watchdog.startObservingHealth(observer1, Arrays.asList(APP_A, APP_B), SHORT_DURATION);
+ watchdog.startObservingHealth(observer1, Arrays.asList(APP_B), SHORT_DURATION);
+
+ // Then fail APP_C (not observed) above the threshold
+ for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+ watchdog.onPackageFailure(new String[]{APP_C});
+ }
+
+ // Run handler so package failures are dispatched to observers
+ mTestLooper.dispatchAll();
- // Then fail APP_A and APP_B above the threshold
+ // Verify that observers are not notified
+ assertEquals(0, observer1.mFailedPackages.size());
+ assertEquals(0, observer2.mFailedPackages.size());
+ }
+
+ /**
+ * Test package failure and notifies only least impact observers.
+ */
+ @Test
+ public void testPackageFailureNotifyAllDifferentImpacts() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver observerNone = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_NONE);
+ TestObserver observerHigh = new TestObserver(OBSERVER_NAME_2,
+ PackageHealthObserverImpact.USER_IMPACT_HIGH);
+ TestObserver observerMid = new TestObserver(OBSERVER_NAME_3,
+ PackageHealthObserverImpact.USER_IMPACT_MEDIUM);
+ TestObserver observerLow = new TestObserver(OBSERVER_NAME_4,
+ PackageHealthObserverImpact.USER_IMPACT_LOW);
+
+ // Start observing for all impact observers
+ watchdog.startObservingHealth(observerNone, Arrays.asList(APP_A, APP_B, APP_C, APP_D),
+ SHORT_DURATION);
+ watchdog.startObservingHealth(observerHigh, Arrays.asList(APP_A, APP_B, APP_C),
+ SHORT_DURATION);
+ watchdog.startObservingHealth(observerMid, Arrays.asList(APP_A, APP_B),
+ SHORT_DURATION);
+ watchdog.startObservingHealth(observerLow, Arrays.asList(APP_A),
+ SHORT_DURATION);
+
+ // Then fail all apps above the threshold
for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
- watchdog.onPackageFailure(new String[]{APP_A, APP_B});
+ watchdog.onPackageFailure(new String[]{APP_A, APP_B, APP_C, APP_D});
}
- // Verify all observers are notifed of all package failures
- List<String> observer1Packages = observer1.mFailedPackages;
- List<String> observer2Packages = observer2.mFailedPackages;
- assertEquals(2, observer1Packages.size());
- assertEquals(1, observer2Packages.size());
- assertEquals(APP_A, observer1Packages.get(0));
- assertEquals(APP_B, observer1Packages.get(1));
- assertEquals(APP_A, observer2Packages.get(0));
+ // Run handler so package failures are dispatched to observers
+ mTestLooper.dispatchAll();
+
+ // Verify least impact observers are notifed of package failures
+ List<String> observerNonePackages = observerNone.mFailedPackages;
+ List<String> observerHighPackages = observerHigh.mFailedPackages;
+ List<String> observerMidPackages = observerMid.mFailedPackages;
+ List<String> observerLowPackages = observerLow.mFailedPackages;
+
+ // APP_D failure observed by only observerNone is not caught cos its impact is none
+ assertEquals(0, observerNonePackages.size());
+ // APP_C failure is caught by observerHigh cos it's the lowest impact observer
+ assertEquals(1, observerHighPackages.size());
+ assertEquals(APP_C, observerHighPackages.get(0));
+ // APP_B failure is caught by observerMid cos it's the lowest impact observer
+ assertEquals(1, observerMidPackages.size());
+ assertEquals(APP_B, observerMidPackages.get(0));
+ // APP_A failure is caught by observerLow cos it's the lowest impact observer
+ assertEquals(1, observerLowPackages.size());
+ assertEquals(APP_A, observerLowPackages.get(0));
}
/**
- * Test package failure and notifies only one observer because it handles the failure
+ * Test package failure and least impact observers are notified successively.
+ * State transistions:
+ *
+ * <ul>
+ * <li>(observer1:low, observer2:mid) -> {observer1}
+ * <li>(observer1:high, observer2:mid) -> {observer2}
+ * <li>(observer1:high, observer2:none) -> {observer1}
+ * <li>(observer1:none, observer2:none) -> {}
+ * <ul>
*/
@Test
- public void testPackageFailureNotifyOne() throws Exception {
+ public void testPackageFailureNotifyLeastSuccessively() throws Exception {
PackageWatchdog watchdog = createWatchdog();
- TestObserver observer1 = new TestObserver(OBSERVER_NAME_1, true /* shouldHandle */);
- TestObserver observer2 = new TestObserver(OBSERVER_NAME_2, true /* shouldHandle */);
+ TestObserver observerFirst = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_LOW);
+ TestObserver observerSecond = new TestObserver(OBSERVER_NAME_2,
+ PackageHealthObserverImpact.USER_IMPACT_MEDIUM);
+
+ // Start observing for observerFirst and observerSecond with failure handling
+ watchdog.startObservingHealth(observerFirst, Arrays.asList(APP_A), LONG_DURATION);
+ watchdog.startObservingHealth(observerSecond, Arrays.asList(APP_A), LONG_DURATION);
+
+ // Then fail APP_A above the threshold
+ for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+ watchdog.onPackageFailure(new String[]{APP_A});
+ }
+ // Run handler so package failures are dispatched to observers
+ mTestLooper.dispatchAll();
+
+ // Verify only observerFirst is notifed
+ assertEquals(1, observerFirst.mFailedPackages.size());
+ assertEquals(APP_A, observerFirst.mFailedPackages.get(0));
+ assertEquals(0, observerSecond.mFailedPackages.size());
+
+ // After observerFirst handles failure, next action it has is high impact
+ observerFirst.mImpact = PackageHealthObserverImpact.USER_IMPACT_HIGH;
+ observerFirst.mFailedPackages.clear();
+ observerSecond.mFailedPackages.clear();
+
+ // Then fail APP_A again above the threshold
+ for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+ watchdog.onPackageFailure(new String[]{APP_A});
+ }
+ // Run handler so package failures are dispatched to observers
+ mTestLooper.dispatchAll();
+
+ // Verify only observerSecond is notifed cos it has least impact
+ assertEquals(1, observerSecond.mFailedPackages.size());
+ assertEquals(APP_A, observerSecond.mFailedPackages.get(0));
+ assertEquals(0, observerFirst.mFailedPackages.size());
+
+ // After observerSecond handles failure, it has no further actions
+ observerSecond.mImpact = PackageHealthObserverImpact.USER_IMPACT_NONE;
+ observerFirst.mFailedPackages.clear();
+ observerSecond.mFailedPackages.clear();
+
+ // Then fail APP_A again above the threshold
+ for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+ watchdog.onPackageFailure(new String[]{APP_A});
+ }
+ // Run handler so package failures are dispatched to observers
+ mTestLooper.dispatchAll();
+
+ // Verify only observerFirst is notifed cos it has the only action
+ assertEquals(1, observerFirst.mFailedPackages.size());
+ assertEquals(APP_A, observerFirst.mFailedPackages.get(0));
+ assertEquals(0, observerSecond.mFailedPackages.size());
+
+ // After observerFirst handles failure, it too has no further actions
+ observerFirst.mImpact = PackageHealthObserverImpact.USER_IMPACT_NONE;
+ observerFirst.mFailedPackages.clear();
+ observerSecond.mFailedPackages.clear();
+
+ // Then fail APP_A again above the threshold
+ for (int i = 0; i < TRIGGER_FAILURE_COUNT; i++) {
+ watchdog.onPackageFailure(new String[]{APP_A});
+ }
+ // Run handler so package failures are dispatched to observers
+ mTestLooper.dispatchAll();
+
+ // Verify no observer is notified cos no actions left
+ assertEquals(0, observerFirst.mFailedPackages.size());
+ assertEquals(0, observerSecond.mFailedPackages.size());
+ }
+
+ /**
+ * Test package failure and notifies only one observer even with observer impact tie.
+ */
+ @Test
+ public void testPackageFailureNotifyOneSameImpact() throws Exception {
+ PackageWatchdog watchdog = createWatchdog();
+ TestObserver observer1 = new TestObserver(OBSERVER_NAME_1,
+ PackageHealthObserverImpact.USER_IMPACT_HIGH);
+ TestObserver observer2 = new TestObserver(OBSERVER_NAME_2,
+ PackageHealthObserverImpact.USER_IMPACT_HIGH);
// Start observing for observer1 and observer2 with failure handling
watchdog.startObservingHealth(observer2, Arrays.asList(APP_A), SHORT_DURATION);
@@ -249,6 +391,9 @@ public class PackageWatchdogTest {
watchdog.onPackageFailure(new String[]{APP_A});
}
+ // Run handler so package failures are dispatched to observers
+ mTestLooper.dispatchAll();
+
// Verify only one observer is notifed
assertEquals(1, observer1.mFailedPackages.size());
assertEquals(APP_A, observer1.mFailedPackages.get(0));
@@ -262,21 +407,26 @@ public class PackageWatchdogTest {
private static class TestObserver implements PackageHealthObserver {
private final String mName;
- private boolean mShouldHandle;
+ private int mImpact;
final List<String> mFailedPackages = new ArrayList<>();
TestObserver(String name) {
mName = name;
+ mImpact = PackageHealthObserverImpact.USER_IMPACT_MEDIUM;
}
- TestObserver(String name, boolean shouldHandle) {
+ TestObserver(String name, int impact) {
mName = name;
- mShouldHandle = shouldHandle;
+ mImpact = impact;
+ }
+
+ public int onHealthCheckFailed(String packageName) {
+ return mImpact;
}
- public boolean onHealthCheckFailed(String packageName) {
+ public boolean execute(String packageName) {
mFailedPackages.add(packageName);
- return mShouldHandle;
+ return true;
}
public String getName() {
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
index 030641bf0895..e10f866c899f 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackBroadcastReceiver.java
@@ -29,7 +29,7 @@ import java.util.concurrent.TimeUnit;
/**
* A broadcast receiver that can be used to get
- * ACTION_PACKAGE_ROLLBACK_EXECUTED broadcasts.
+ * ACTION_ROLLBACK_COMMITTED broadcasts.
*/
class RollbackBroadcastReceiver extends BroadcastReceiver {
@@ -43,7 +43,7 @@ class RollbackBroadcastReceiver extends BroadcastReceiver {
*/
RollbackBroadcastReceiver() {
IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
+ filter.addAction(Intent.ACTION_ROLLBACK_COMMITTED);
InstrumentationRegistry.getContext().registerReceiver(this, filter);
}
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 13ac4f09dd86..0493ef8ab062 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -31,11 +31,8 @@ import android.support.test.InstrumentationRegistry;
import android.util.Log;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Ignore;
@@ -43,6 +40,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -86,8 +84,8 @@ public class RollbackTest {
Manifest.permission.DELETE_PACKAGES,
Manifest.permission.MANAGE_ROLLBACKS);
- // Register a broadcast receiver for notification when the rollback is
- // done executing.
+ // Register a broadcast receiver for notification when the
+ // rollback has been committed.
RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
RollbackManager rm = RollbackTestUtils.getRollbackManager();
@@ -99,12 +97,11 @@ public class RollbackTest {
// uninstalled and when rollback manager deletes the rollback. Fix it
// so that's not the case!
for (int i = 0; i < 5; ++i) {
- for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
- if (TEST_APP_A.equals(info.targetPackage.getPackageName())) {
- Log.i(TAG, "Sleeping 1 second to wait for uninstall to take effect.");
- Thread.sleep(1000);
- break;
- }
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
+ if (rollback != null) {
+ Log.i(TAG, "Sleeping 1 second to wait for uninstall to take effect.");
+ Thread.sleep(1000);
}
}
@@ -113,13 +110,11 @@ public class RollbackTest {
// between when the app is uninstalled and when the previously
// available rollback, if any, is removed.
Thread.sleep(1000);
- assertNull(rm.getAvailableRollback(TEST_APP_A));
- assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+ assertNull(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A));
- // There should be no recently executed rollbacks for this package.
- for (RollbackInfo info : rm.getRecentlyExecutedRollbacks()) {
- assertNotEquals(TEST_APP_A, info.targetPackage.getPackageName());
- }
+ // There should be no recently committed rollbacks for this package.
+ assertNull(getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TEST_APP_A));
// Install v1 of the app (without rollbacks enabled).
RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
@@ -134,10 +129,9 @@ public class RollbackTest {
// between when the app is installed and when the rollback
// is made available.
Thread.sleep(1000);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
- RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollback);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
// We should not have received any rollback requests yet.
// TODO: Possibly flaky if, by chance, some other app on device
@@ -145,7 +139,7 @@ public class RollbackTest {
assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
// Roll back the app.
- RollbackTestUtils.rollback(rollback);
+ RollbackTestUtils.rollback(rollback.getRollbackId());
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
// Verify we received a broadcast for the rollback.
@@ -156,15 +150,9 @@ public class RollbackTest {
assertNull(broadcastReceiver.poll(0, TimeUnit.SECONDS));
// Verify the recent rollback has been recorded.
- rollback = null;
- for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
- if (TEST_APP_A.equals(r.targetPackage.getPackageName())) {
- assertNull(rollback);
- rollback = r;
- }
- }
- assertNotNull(rollback);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+ rollback = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
broadcastReceiver.unregister();
context.unregisterReceiver(enableRollbackReceiver);
@@ -202,31 +190,28 @@ public class RollbackTest {
// is made available.
Thread.sleep(1000);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
- RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollbackA);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
+ RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
- RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
- assertNotNull(rollbackB);
- assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
+ RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_B);
+ assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
// Reload the persisted data.
rm.reloadPersistedData();
// The apps should still be available for rollback.
- rollbackA = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollbackA);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
+ rollbackA = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
- rollbackB = rm.getAvailableRollback(TEST_APP_B);
- assertNotNull(rollbackB);
- assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
+ rollbackB = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_B);
+ assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
// Rollback of B should not rollback A
- RollbackTestUtils.rollback(rollbackB);
+ RollbackTestUtils.rollback(rollbackB.getRollbackId());
assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
} finally {
@@ -264,31 +249,26 @@ public class RollbackTest {
// is made available.
Thread.sleep(1000);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
- RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollbackA);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
+ RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoForAandB(rollbackA);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
- RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
- assertNotNull(rollbackB);
- assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
+ RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_B);
+ assertRollbackInfoForAandB(rollbackB);
// Reload the persisted data.
rm.reloadPersistedData();
// The apps should still be available for rollback.
- rollbackA = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollbackA);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA.targetPackage);
+ rollbackA = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoForAandB(rollbackA);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_B));
- rollbackB = rm.getAvailableRollback(TEST_APP_B);
- assertNotNull(rollbackB);
- assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB.targetPackage);
+ rollbackB = getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(), TEST_APP_B);
+ assertRollbackInfoForAandB(rollbackB);
// Rollback of B should rollback A as well
- RollbackTestUtils.rollback(rollbackB);
+ RollbackTestUtils.rollback(rollbackB.getRollbackId());
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
} finally {
@@ -297,10 +277,10 @@ public class RollbackTest {
}
/**
- * Test that recently executed rollback data is properly persisted.
+ * Test that recently committed rollback data is properly persisted.
*/
@Test
- public void testRecentlyExecutedRollbackPersistence() throws Exception {
+ public void testRecentlyCommittedRollbackPersistence() throws Exception {
try {
RollbackTestUtils.adoptShellPermissionIdentity(
Manifest.permission.INSTALL_PACKAGES,
@@ -319,37 +299,27 @@ public class RollbackTest {
// between when the app is installed and when the rollback
// is made available.
Thread.sleep(1000);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
- RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
// Roll back the app.
- RollbackTestUtils.rollback(rollback);
+ RollbackTestUtils.rollback(rollback.getRollbackId());
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
// Verify the recent rollback has been recorded.
- rollback = null;
- for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
- if (TEST_APP_A.equals(r.targetPackage.getPackageName())) {
- assertNull(rollback);
- rollback = r;
- }
- }
+ rollback = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
assertNotNull(rollback);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
// Reload the persisted data.
rm.reloadPersistedData();
// Verify the recent rollback is still recorded.
- rollback = null;
- for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
- if (TEST_APP_A.equals(r.targetPackage.getPackageName())) {
- assertNull(rollback);
- rollback = r;
- }
- }
+ rollback = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
assertNotNull(rollback);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
} finally {
RollbackTestUtils.dropShellPermissionIdentity();
}
@@ -378,17 +348,16 @@ public class RollbackTest {
// between when the app is installed and when the rollback
// is made available.
Thread.sleep(1000);
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
- RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollback);
- assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.targetPackage);
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollback);
// Expire the rollback.
rm.expireRollbackForPackage(TEST_APP_A);
// The rollback should no longer be available.
- assertNull(rm.getAvailableRollback(TEST_APP_A));
- assertFalse(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
+ assertNull(getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A));
} finally {
RollbackTestUtils.dropShellPermissionIdentity();
}
@@ -459,8 +428,9 @@ public class RollbackTest {
processUserData(TEST_APP_A);
RollbackManager rm = RollbackTestUtils.getRollbackManager();
- RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
- RollbackTestUtils.rollback(rollback);
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ RollbackTestUtils.rollback(rollback.getRollbackId());
processUserData(TEST_APP_A);
} finally {
RollbackTestUtils.dropShellPermissionIdentity();
@@ -469,12 +439,12 @@ public class RollbackTest {
/**
* Test restrictions on rollback broadcast sender.
- * A random app should not be able to send a PACKAGE_ROLLBACK_EXECUTED broadcast.
+ * A random app should not be able to send a ROLLBACK_COMMITTED broadcast.
*/
@Test
public void testRollbackBroadcastRestrictions() throws Exception {
RollbackBroadcastReceiver broadcastReceiver = new RollbackBroadcastReceiver();
- Intent broadcast = new Intent(Intent.ACTION_PACKAGE_ROLLBACK_EXECUTED);
+ Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED);
try {
InstrumentationRegistry.getContext().sendBroadcast(broadcast);
fail("Succeeded in sending restricted broadcast from app context.");
@@ -516,21 +486,21 @@ public class RollbackTest {
assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
// Both test apps should now be available for rollback, and the
- // targetPackage returned for rollback should be correct.
+ // RollbackInfo returned for the rollbacks should be correct.
// TODO: See if there is a way to remove this race condition
// between when the app is installed and when the rollback
// is made available.
Thread.sleep(1000);
- RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollbackA);
- assertEquals(TEST_APP_A, rollbackA.targetPackage.getPackageName());
+ RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
- RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
- assertNotNull(rollbackB);
- assertEquals(TEST_APP_B, rollbackB.targetPackage.getPackageName());
+ RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_B);
+ assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
// Executing rollback should roll back the correct package.
- RollbackTestUtils.rollback(rollbackA);
+ RollbackTestUtils.rollback(rollbackA.getRollbackId());
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
@@ -539,7 +509,7 @@ public class RollbackTest {
RollbackTestUtils.install("RollbackTestAppAv2.apk", true);
assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
- RollbackTestUtils.rollback(rollbackB);
+ RollbackTestUtils.rollback(rollbackB.getRollbackId());
assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
} finally {
@@ -558,21 +528,14 @@ public class RollbackTest {
RollbackManager rm = RollbackTestUtils.getRollbackManager();
try {
- rm.getAvailableRollback(TEST_APP_A);
- fail("expected SecurityException");
- } catch (SecurityException e) {
- // Expected.
- }
-
- try {
- rm.getPackagesWithAvailableRollbacks();
+ rm.getAvailableRollbacks();
fail("expected SecurityException");
} catch (SecurityException e) {
// Expected.
}
try {
- rm.getRecentlyExecutedRollbacks();
+ rm.getRecentlyCommittedRollbacks();
fail("expected SecurityException");
} catch (SecurityException e) {
// Expected.
@@ -581,7 +544,7 @@ public class RollbackTest {
try {
// TODO: What if the implementation checks arguments for non-null
// first? Then this test isn't valid.
- rm.executeRollback(null, null);
+ rm.commitRollback(0, null);
fail("expected SecurityException");
} catch (SecurityException e) {
// Expected.
@@ -629,27 +592,26 @@ public class RollbackTest {
assertEquals(2, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
// TEST_APP_A should now be available for rollback.
- assertTrue(rm.getPackagesWithAvailableRollbacks().contains(TEST_APP_A));
- RollbackInfo rollback = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollback);
-
- // TODO: Test the dependent apps for rollback are correct once we
- // support that in the RollbackInfo API.
+ RollbackInfo rollback = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoForAandB(rollback);
// Rollback the app. It should cause both test apps to be rolled
// back.
- RollbackTestUtils.rollback(rollback);
+ RollbackTestUtils.rollback(rollback.getRollbackId());
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_B));
- // We should not see a recent rollback listed for TEST_APP_B
- for (RollbackInfo r : rm.getRecentlyExecutedRollbacks()) {
- assertNotEquals(TEST_APP_B, r.targetPackage.getPackageName());
- }
+ // We should see recent rollbacks listed for both A and B.
+ Thread.sleep(1000);
+ RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TEST_APP_A);
- // TODO: Test the listed dependent apps for the recently executed
- // rollback are correct once we support that in the RollbackInfo
- // API.
+ RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
+ rm.getRecentlyCommittedRollbacks(), TEST_APP_B);
+ assertRollbackInfoForAandB(rollbackB);
+
+ assertEquals(rollbackA.getRollbackId(), rollbackB.getRollbackId());
} finally {
RollbackTestUtils.dropShellPermissionIdentity();
}
@@ -697,13 +659,13 @@ public class RollbackTest {
// between when the app is installed and when the rollback
// is made available.
Thread.sleep(1000);
- RollbackInfo rollbackA = rm.getAvailableRollback(TEST_APP_A);
- assertNotNull(rollbackA);
- assertEquals(TEST_APP_A, rollbackA.targetPackage.getPackageName());
+ RollbackInfo rollbackA = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_A);
+ assertRollbackInfoEquals(TEST_APP_A, 2, 1, rollbackA);
- RollbackInfo rollbackB = rm.getAvailableRollback(TEST_APP_B);
- assertNotNull(rollbackB);
- assertEquals(TEST_APP_B, rollbackB.targetPackage.getPackageName());
+ RollbackInfo rollbackB = getUniqueRollbackInfoForPackage(
+ rm.getAvailableRollbacks(), TEST_APP_B);
+ assertRollbackInfoEquals(TEST_APP_B, 2, 1, rollbackB);
// Start apps PackageWatchdog#TRIGGER_FAILURE_COUNT times so TEST_APP_A crashes
for (int i = 0; i < 5; i++) {
@@ -724,4 +686,47 @@ public class RollbackTest {
RollbackTestUtils.dropShellPermissionIdentity();
}
}
+
+ // Helper function to test the value of a RollbackInfo with single package
+ private void assertRollbackInfoEquals(String packageName,
+ long versionRolledBackFrom, long versionRolledBackTo,
+ RollbackInfo info) {
+ assertNotNull(info);
+ assertEquals(1, info.getPackages().size());
+ assertPackageRollbackInfoEquals(packageName, versionRolledBackFrom, versionRolledBackTo,
+ info.getPackages().get(0));
+ }
+
+ // Helper function to test that the given rollback info is a rollback for
+ // the atomic set {A2, B2} -> {A1, B1}.
+ private void assertRollbackInfoForAandB(RollbackInfo rollback) {
+ assertNotNull(rollback);
+ assertEquals(2, rollback.getPackages().size());
+ if (TEST_APP_A.equals(rollback.getPackages().get(0).getPackageName())) {
+ assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.getPackages().get(0));
+ assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollback.getPackages().get(1));
+ } else {
+ assertPackageRollbackInfoEquals(TEST_APP_B, 2, 1, rollback.getPackages().get(0));
+ assertPackageRollbackInfoEquals(TEST_APP_A, 2, 1, rollback.getPackages().get(1));
+ }
+ }
+
+ // Helper function to return the RollbackInfo with a given package in the
+ // list of rollbacks. Throws an assertion failure if there is more than
+ // one such rollback info. Returns null if there are no such rollback
+ // infos.
+ private RollbackInfo getUniqueRollbackInfoForPackage(List<RollbackInfo> rollbacks,
+ String packageName) {
+ RollbackInfo found = null;
+ for (RollbackInfo rollback : rollbacks) {
+ for (PackageRollbackInfo info : rollback.getPackages()) {
+ if (packageName.equals(info.getPackageName())) {
+ assertNull(found);
+ found = rollback;
+ break;
+ }
+ }
+ }
+ return found;
+ }
}
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index edb13556b8fc..14786577c814 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -21,7 +21,6 @@ import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
-import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.support.test.InstrumentationRegistry;
@@ -90,12 +89,12 @@ class RollbackTestUtils {
}
/**
- * Execute the given rollback.
+ * Commit the given rollback.
* @throws AssertionError if the rollback fails.
*/
- static void rollback(RollbackInfo rollback) throws InterruptedException {
+ static void rollback(int rollbackId) throws InterruptedException {
RollbackManager rm = getRollbackManager();
- rm.executeRollback(rollback, LocalIntentSender.getIntentSender());
+ rm.commitRollback(rollbackId, LocalIntentSender.getIntentSender());
assertStatusSuccess(LocalIntentSender.getIntentSenderResult());
}
diff --git a/tests/net/java/android/net/NetworkUtilsTest.java b/tests/net/java/android/net/NetworkUtilsTest.java
index 3452819835f5..ba6e0f299057 100644
--- a/tests/net/java/android/net/NetworkUtilsTest.java
+++ b/tests/net/java/android/net/NetworkUtilsTest.java
@@ -16,161 +16,19 @@
package android.net;
-import static android.net.NetworkUtils.getImplicitNetmask;
-import static android.net.NetworkUtils.inet4AddressToIntHTH;
-import static android.net.NetworkUtils.inet4AddressToIntHTL;
-import static android.net.NetworkUtils.intToInet4AddressHTH;
-import static android.net.NetworkUtils.intToInet4AddressHTL;
-import static android.net.NetworkUtils.netmaskToPrefixLength;
-import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTH;
-import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTL;
-import static android.net.NetworkUtils.getBroadcastAddress;
-import static android.net.NetworkUtils.getPrefixMaskAsInet4Address;
-
import static junit.framework.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
import android.support.test.runner.AndroidJUnit4;
-import java.math.BigInteger;
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.util.TreeSet;
-
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.math.BigInteger;
+import java.util.TreeSet;
+
@RunWith(AndroidJUnit4.class)
@android.support.test.filters.SmallTest
public class NetworkUtilsTest {
-
- private InetAddress Address(String addr) {
- return InetAddress.parseNumericAddress(addr);
- }
-
- private Inet4Address IPv4Address(String addr) {
- return (Inet4Address) Address(addr);
- }
-
- @Test
- public void testGetImplicitNetmask() {
- assertEquals(8, getImplicitNetmask(IPv4Address("4.2.2.2")));
- assertEquals(8, getImplicitNetmask(IPv4Address("10.5.6.7")));
- assertEquals(16, getImplicitNetmask(IPv4Address("173.194.72.105")));
- assertEquals(16, getImplicitNetmask(IPv4Address("172.23.68.145")));
- assertEquals(24, getImplicitNetmask(IPv4Address("192.0.2.1")));
- assertEquals(24, getImplicitNetmask(IPv4Address("192.168.5.1")));
- assertEquals(32, getImplicitNetmask(IPv4Address("224.0.0.1")));
- assertEquals(32, getImplicitNetmask(IPv4Address("255.6.7.8")));
- }
-
- private void assertInvalidNetworkMask(Inet4Address addr) {
- try {
- netmaskToPrefixLength(addr);
- fail("Invalid netmask " + addr.getHostAddress() + " did not cause exception");
- } catch (IllegalArgumentException expected) {
- }
- }
-
- @Test
- public void testInet4AddressToIntHTL() {
- assertEquals(0, inet4AddressToIntHTL(IPv4Address("0.0.0.0")));
- assertEquals(0x000080ff, inet4AddressToIntHTL(IPv4Address("255.128.0.0")));
- assertEquals(0x0080ff0a, inet4AddressToIntHTL(IPv4Address("10.255.128.0")));
- assertEquals(0x00feff0a, inet4AddressToIntHTL(IPv4Address("10.255.254.0")));
- assertEquals(0xfeffa8c0, inet4AddressToIntHTL(IPv4Address("192.168.255.254")));
- assertEquals(0xffffa8c0, inet4AddressToIntHTL(IPv4Address("192.168.255.255")));
- }
-
- @Test
- public void testIntToInet4AddressHTL() {
- assertEquals(IPv4Address("0.0.0.0"), intToInet4AddressHTL(0));
- assertEquals(IPv4Address("255.128.0.0"), intToInet4AddressHTL(0x000080ff));
- assertEquals(IPv4Address("10.255.128.0"), intToInet4AddressHTL(0x0080ff0a));
- assertEquals(IPv4Address("10.255.254.0"), intToInet4AddressHTL(0x00feff0a));
- assertEquals(IPv4Address("192.168.255.254"), intToInet4AddressHTL(0xfeffa8c0));
- assertEquals(IPv4Address("192.168.255.255"), intToInet4AddressHTL(0xffffa8c0));
- }
-
- @Test
- public void testInet4AddressToIntHTH() {
- assertEquals(0, inet4AddressToIntHTH(IPv4Address("0.0.0.0")));
- assertEquals(0xff800000, inet4AddressToIntHTH(IPv4Address("255.128.0.0")));
- assertEquals(0x0aff8000, inet4AddressToIntHTH(IPv4Address("10.255.128.0")));
- assertEquals(0x0afffe00, inet4AddressToIntHTH(IPv4Address("10.255.254.0")));
- assertEquals(0xc0a8fffe, inet4AddressToIntHTH(IPv4Address("192.168.255.254")));
- assertEquals(0xc0a8ffff, inet4AddressToIntHTH(IPv4Address("192.168.255.255")));
- }
-
- @Test
- public void testIntToInet4AddressHTH() {
- assertEquals(IPv4Address("0.0.0.0"), intToInet4AddressHTH(0));
- assertEquals(IPv4Address("255.128.0.0"), intToInet4AddressHTH(0xff800000));
- assertEquals(IPv4Address("10.255.128.0"), intToInet4AddressHTH(0x0aff8000));
- assertEquals(IPv4Address("10.255.254.0"), intToInet4AddressHTH(0x0afffe00));
- assertEquals(IPv4Address("192.168.255.254"), intToInet4AddressHTH(0xc0a8fffe));
- assertEquals(IPv4Address("192.168.255.255"), intToInet4AddressHTH(0xc0a8ffff));
- }
-
- @Test
- public void testNetmaskToPrefixLength() {
- assertEquals(0, netmaskToPrefixLength(IPv4Address("0.0.0.0")));
- assertEquals(9, netmaskToPrefixLength(IPv4Address("255.128.0.0")));
- assertEquals(17, netmaskToPrefixLength(IPv4Address("255.255.128.0")));
- assertEquals(23, netmaskToPrefixLength(IPv4Address("255.255.254.0")));
- assertEquals(31, netmaskToPrefixLength(IPv4Address("255.255.255.254")));
- assertEquals(32, netmaskToPrefixLength(IPv4Address("255.255.255.255")));
-
- assertInvalidNetworkMask(IPv4Address("0.0.0.1"));
- assertInvalidNetworkMask(IPv4Address("255.255.255.253"));
- assertInvalidNetworkMask(IPv4Address("255.255.0.255"));
- }
-
- @Test
- public void testPrefixLengthToV4NetmaskIntHTL() {
- assertEquals(0, prefixLengthToV4NetmaskIntHTL(0));
- assertEquals(0x000080ff /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTL(9));
- assertEquals(0x0080ffff /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTL(17));
- assertEquals(0x00feffff /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTL(23));
- assertEquals(0xfeffffff /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTL(31));
- assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTL(32));
- }
-
- @Test
- public void testPrefixLengthToV4NetmaskIntHTH() {
- assertEquals(0, prefixLengthToV4NetmaskIntHTH(0));
- assertEquals(0xff800000 /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTH(9));
- assertEquals(0xffff8000 /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTH(17));
- assertEquals(0xfffffe00 /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTH(23));
- assertEquals(0xfffffffe /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTH(31));
- assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTH(32));
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testPrefixLengthToV4NetmaskIntHTH_NegativeLength() {
- prefixLengthToV4NetmaskIntHTH(-1);
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testPrefixLengthToV4NetmaskIntHTH_LengthTooLarge() {
- prefixLengthToV4NetmaskIntHTH(33);
- }
-
- private void checkAddressMasking(String expectedAddr, String addr, int prefixLength) {
- final int prefix = prefixLengthToV4NetmaskIntHTH(prefixLength);
- final int addrInt = inet4AddressToIntHTH(IPv4Address(addr));
- assertEquals(IPv4Address(expectedAddr), intToInet4AddressHTH(prefix & addrInt));
- }
-
- @Test
- public void testPrefixLengthToV4NetmaskIntHTH_MaskAddr() {
- checkAddressMasking("192.168.0.0", "192.168.128.1", 16);
- checkAddressMasking("255.240.0.0", "255.255.255.255", 12);
- checkAddressMasking("255.255.255.255", "255.255.255.255", 32);
- checkAddressMasking("0.0.0.0", "255.255.255.255", 0);
- }
-
@Test
public void testRoutedIPv4AddressCount() {
final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
@@ -267,44 +125,4 @@ public class NetworkUtilsTest {
assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536),
NetworkUtils.routedIPv6AddressCount(set));
}
-
- @Test
- public void testGetPrefixMaskAsAddress() {
- assertEquals("255.255.240.0", getPrefixMaskAsInet4Address(20).getHostAddress());
- assertEquals("255.0.0.0", getPrefixMaskAsInet4Address(8).getHostAddress());
- assertEquals("0.0.0.0", getPrefixMaskAsInet4Address(0).getHostAddress());
- assertEquals("255.255.255.255", getPrefixMaskAsInet4Address(32).getHostAddress());
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testGetPrefixMaskAsAddress_PrefixTooLarge() {
- getPrefixMaskAsInet4Address(33);
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testGetPrefixMaskAsAddress_NegativePrefix() {
- getPrefixMaskAsInet4Address(-1);
- }
-
- @Test
- public void testGetBroadcastAddress() {
- assertEquals("192.168.15.255",
- getBroadcastAddress(IPv4Address("192.168.0.123"), 20).getHostAddress());
- assertEquals("192.255.255.255",
- getBroadcastAddress(IPv4Address("192.168.0.123"), 8).getHostAddress());
- assertEquals("192.168.0.123",
- getBroadcastAddress(IPv4Address("192.168.0.123"), 32).getHostAddress());
- assertEquals("255.255.255.255",
- getBroadcastAddress(IPv4Address("192.168.0.123"), 0).getHostAddress());
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testGetBroadcastAddress_PrefixTooLarge() {
- getBroadcastAddress(IPv4Address("192.168.0.123"), 33);
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testGetBroadcastAddress_NegativePrefix() {
- getBroadcastAddress(IPv4Address("192.168.0.123"), -1);
- }
}
diff --git a/tests/net/java/android/net/StaticIpConfigurationTest.java b/tests/net/java/android/net/StaticIpConfigurationTest.java
index 5bb573455358..2b5ad378e0ae 100644
--- a/tests/net/java/android/net/StaticIpConfigurationTest.java
+++ b/tests/net/java/android/net/StaticIpConfigurationTest.java
@@ -26,13 +26,13 @@ import android.os.Parcel;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.net.InetAddress;
import java.util.HashSet;
import java.util.Objects;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public class StaticIpConfigurationTest {
@@ -203,7 +203,7 @@ public class StaticIpConfigurationTest {
try {
s.writeToParcel(p, 0);
p.setDataPosition(0);
- s2 = StaticIpConfiguration.CREATOR.createFromParcel(p);
+ s2 = StaticIpConfiguration.readFromParcel(p);
} finally {
p.recycle();
}
diff --git a/tests/net/java/android/net/ip/IpServerTest.java b/tests/net/java/android/net/ip/IpServerTest.java
index 80aac047a723..f7542a7b4bfa 100644
--- a/tests/net/java/android/net/ip/IpServerTest.java
+++ b/tests/net/java/android/net/ip/IpServerTest.java
@@ -22,11 +22,11 @@ import static android.net.ConnectivityManager.TETHERING_WIFI;
import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
-import static android.net.NetworkUtils.intToInet4AddressHTH;
import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
import static android.net.ip.IpServer.STATE_AVAILABLE;
import static android.net.ip.IpServer.STATE_TETHERED;
import static android.net.ip.IpServer.STATE_UNAVAILABLE;
+import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
diff --git a/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java b/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java
new file mode 100644
index 000000000000..6da851400af1
--- /dev/null
+++ b/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.shared;
+
+import static android.net.shared.Inet4AddressUtils.getBroadcastAddress;
+import static android.net.shared.Inet4AddressUtils.getImplicitNetmask;
+import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address;
+import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH;
+import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTL;
+import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
+import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTL;
+import static android.net.shared.Inet4AddressUtils.netmaskToPrefixLength;
+import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH;
+import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.junit.Assert.fail;
+
+import android.net.InetAddresses;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.Inet4Address;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class Inet4AddressUtilsTest {
+
+ @Test
+ public void testInet4AddressToIntHTL() {
+ assertEquals(0, inet4AddressToIntHTL(ipv4Address("0.0.0.0")));
+ assertEquals(0x000080ff, inet4AddressToIntHTL(ipv4Address("255.128.0.0")));
+ assertEquals(0x0080ff0a, inet4AddressToIntHTL(ipv4Address("10.255.128.0")));
+ assertEquals(0x00feff0a, inet4AddressToIntHTL(ipv4Address("10.255.254.0")));
+ assertEquals(0xfeffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.254")));
+ assertEquals(0xffffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.255")));
+ }
+
+ @Test
+ public void testIntToInet4AddressHTL() {
+ assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTL(0));
+ assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTL(0x000080ff));
+ assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTL(0x0080ff0a));
+ assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTL(0x00feff0a));
+ assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTL(0xfeffa8c0));
+ assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTL(0xffffa8c0));
+ }
+
+ @Test
+ public void testInet4AddressToIntHTH() {
+ assertEquals(0, inet4AddressToIntHTH(ipv4Address("0.0.0.0")));
+ assertEquals(0xff800000, inet4AddressToIntHTH(ipv4Address("255.128.0.0")));
+ assertEquals(0x0aff8000, inet4AddressToIntHTH(ipv4Address("10.255.128.0")));
+ assertEquals(0x0afffe00, inet4AddressToIntHTH(ipv4Address("10.255.254.0")));
+ assertEquals(0xc0a8fffe, inet4AddressToIntHTH(ipv4Address("192.168.255.254")));
+ assertEquals(0xc0a8ffff, inet4AddressToIntHTH(ipv4Address("192.168.255.255")));
+ }
+
+ @Test
+ public void testIntToInet4AddressHTH() {
+ assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTH(0));
+ assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTH(0xff800000));
+ assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTH(0x0aff8000));
+ assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTH(0x0afffe00));
+ assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTH(0xc0a8fffe));
+ assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTH(0xc0a8ffff));
+ }
+
+
+ @Test
+ public void testPrefixLengthToV4NetmaskIntHTL() {
+ assertEquals(0, prefixLengthToV4NetmaskIntHTL(0));
+ assertEquals(0x000080ff /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTL(9));
+ assertEquals(0x0080ffff /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTL(17));
+ assertEquals(0x00feffff /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTL(23));
+ assertEquals(0xfeffffff /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTL(31));
+ assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTL(32));
+ }
+
+ @Test
+ public void testPrefixLengthToV4NetmaskIntHTH() {
+ assertEquals(0, prefixLengthToV4NetmaskIntHTH(0));
+ assertEquals(0xff800000 /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTH(9));
+ assertEquals(0xffff8000 /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTH(17));
+ assertEquals(0xfffffe00 /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTH(23));
+ assertEquals(0xfffffffe /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTH(31));
+ assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTH(32));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testPrefixLengthToV4NetmaskIntHTH_NegativeLength() {
+ prefixLengthToV4NetmaskIntHTH(-1);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testPrefixLengthToV4NetmaskIntHTH_LengthTooLarge() {
+ prefixLengthToV4NetmaskIntHTH(33);
+ }
+
+ private void checkAddressMasking(String expectedAddr, String addr, int prefixLength) {
+ final int prefix = prefixLengthToV4NetmaskIntHTH(prefixLength);
+ final int addrInt = inet4AddressToIntHTH(ipv4Address(addr));
+ assertEquals(ipv4Address(expectedAddr), intToInet4AddressHTH(prefix & addrInt));
+ }
+
+ @Test
+ public void testPrefixLengthToV4NetmaskIntHTH_MaskAddr() {
+ checkAddressMasking("192.168.0.0", "192.168.128.1", 16);
+ checkAddressMasking("255.240.0.0", "255.255.255.255", 12);
+ checkAddressMasking("255.255.255.255", "255.255.255.255", 32);
+ checkAddressMasking("0.0.0.0", "255.255.255.255", 0);
+ }
+
+ @Test
+ public void testGetImplicitNetmask() {
+ assertEquals(8, getImplicitNetmask(ipv4Address("4.2.2.2")));
+ assertEquals(8, getImplicitNetmask(ipv4Address("10.5.6.7")));
+ assertEquals(16, getImplicitNetmask(ipv4Address("173.194.72.105")));
+ assertEquals(16, getImplicitNetmask(ipv4Address("172.23.68.145")));
+ assertEquals(24, getImplicitNetmask(ipv4Address("192.0.2.1")));
+ assertEquals(24, getImplicitNetmask(ipv4Address("192.168.5.1")));
+ assertEquals(32, getImplicitNetmask(ipv4Address("224.0.0.1")));
+ assertEquals(32, getImplicitNetmask(ipv4Address("255.6.7.8")));
+ }
+
+ private void assertInvalidNetworkMask(Inet4Address addr) {
+ try {
+ netmaskToPrefixLength(addr);
+ fail("Invalid netmask " + addr.getHostAddress() + " did not cause exception");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testNetmaskToPrefixLength() {
+ assertEquals(0, netmaskToPrefixLength(ipv4Address("0.0.0.0")));
+ assertEquals(9, netmaskToPrefixLength(ipv4Address("255.128.0.0")));
+ assertEquals(17, netmaskToPrefixLength(ipv4Address("255.255.128.0")));
+ assertEquals(23, netmaskToPrefixLength(ipv4Address("255.255.254.0")));
+ assertEquals(31, netmaskToPrefixLength(ipv4Address("255.255.255.254")));
+ assertEquals(32, netmaskToPrefixLength(ipv4Address("255.255.255.255")));
+
+ assertInvalidNetworkMask(ipv4Address("0.0.0.1"));
+ assertInvalidNetworkMask(ipv4Address("255.255.255.253"));
+ assertInvalidNetworkMask(ipv4Address("255.255.0.255"));
+ }
+
+ @Test
+ public void testGetPrefixMaskAsAddress() {
+ assertEquals("255.255.240.0", getPrefixMaskAsInet4Address(20).getHostAddress());
+ assertEquals("255.0.0.0", getPrefixMaskAsInet4Address(8).getHostAddress());
+ assertEquals("0.0.0.0", getPrefixMaskAsInet4Address(0).getHostAddress());
+ assertEquals("255.255.255.255", getPrefixMaskAsInet4Address(32).getHostAddress());
+ }
+
+ @Test
+ public void testGetBroadcastAddress() {
+ assertEquals("192.168.15.255",
+ getBroadcastAddress(ipv4Address("192.168.0.123"), 20).getHostAddress());
+ assertEquals("192.255.255.255",
+ getBroadcastAddress(ipv4Address("192.168.0.123"), 8).getHostAddress());
+ assertEquals("192.168.0.123",
+ getBroadcastAddress(ipv4Address("192.168.0.123"), 32).getHostAddress());
+ assertEquals("255.255.255.255",
+ getBroadcastAddress(ipv4Address("192.168.0.123"), 0).getHostAddress());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testGetBroadcastAddress_PrefixTooLarge() {
+ getBroadcastAddress(ipv4Address("192.168.0.123"), 33);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testGetBroadcastAddress_NegativePrefix() {
+ getBroadcastAddress(ipv4Address("192.168.0.123"), -1);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testGetPrefixMaskAsAddress_PrefixTooLarge() {
+ getPrefixMaskAsInet4Address(33);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testGetPrefixMaskAsAddress_NegativePrefix() {
+ getPrefixMaskAsInet4Address(-1);
+ }
+
+ private Inet4Address ipv4Address(String addr) {
+ return (Inet4Address) InetAddresses.parseNumericAddress(addr);
+ }
+}
diff --git a/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java b/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java
index 14df392cbe07..fb4d43c367db 100644
--- a/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java
+++ b/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java
@@ -62,7 +62,7 @@ public class IpConfigurationParcelableUtilTest {
mDhcpResults.leaseDuration = 3600;
mDhcpResults.mtu = 1450;
// Any added DhcpResults field must be included in equals() to be tested properly
- assertFieldCountEquals(4, DhcpResults.class);
+ assertFieldCountEquals(8, DhcpResults.class);
}
@Test
diff --git a/tools/bit/aapt.cpp b/tools/bit/aapt.cpp
index 961b47cdfecd..cee0cd52a546 100644
--- a/tools/bit/aapt.cpp
+++ b/tools/bit/aapt.cpp
@@ -159,10 +159,11 @@ int
inspect_apk(Apk* apk, const string& filename)
{
// Load the manifest xml
- Command cmd("aapt");
+ Command cmd("aapt2");
cmd.AddArg("dump");
cmd.AddArg("xmltree");
cmd.AddArg(filename);
+ cmd.AddArg("--file");
cmd.AddArg("AndroidManifest.xml");
int err;
@@ -217,11 +218,11 @@ inspect_apk(Apk* apk, const string& filename)
if (current != NULL) {
Attribute attr;
string str = match[2];
- size_t colon = str.find(':');
+ size_t colon = str.rfind(':');
if (colon == string::npos) {
attr.name = str;
} else {
- attr.ns = scope->namespaces[string(str, 0, colon)];
+ attr.ns.assign(str, 0, colon);
attr.name.assign(str, colon+1, string::npos);
}
attr.value = match[3];
diff --git a/tools/bit/main.cpp b/tools/bit/main.cpp
index a71cea1c44f9..860094aef1f4 100644
--- a/tools/bit/main.cpp
+++ b/tools/bit/main.cpp
@@ -623,12 +623,13 @@ run_phases(vector<Target*> targets, const Options& options)
const string buildProduct = get_required_env("TARGET_PRODUCT", false);
const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
-
+ const string buildOut = get_out_dir();
chdir_or_exit(buildTop.c_str());
- const string buildDevice = get_build_var("TARGET_DEVICE", false);
- const string buildId = get_build_var("BUILD_ID", false);
- const string buildOut = get_out_dir();
+ BuildVars buildVars(buildOut, buildProduct, buildVariant, buildType);
+
+ const string buildDevice = buildVars.GetBuildVar("TARGET_DEVICE", false);
+ const string buildId = buildVars.GetBuildVar("BUILD_ID", false);
// Get the modules for the targets
map<string,Module> modules;
@@ -661,6 +662,7 @@ run_phases(vector<Target*> targets, const Options& options)
string dataPath = buildOut + "/target/product/" + buildDevice + "/data/";
bool syncSystem = false;
bool alwaysSyncSystem = false;
+ vector<string> systemFiles;
vector<InstallApk> installApks;
for (size_t i=0; i<targets.size(); i++) {
Target* target = targets[i];
@@ -670,6 +672,7 @@ run_phases(vector<Target*> targets, const Options& options)
// System partition
if (starts_with(file, systemPath)) {
syncSystem = true;
+ systemFiles.push_back(file);
if (!target->build) {
// If a system partition target didn't get built then
// it won't change we will always need to do adb sync
@@ -692,6 +695,19 @@ run_phases(vector<Target*> targets, const Options& options)
get_directory_contents(systemPath, &systemFilesBefore);
}
+ if (systemFiles.size() > 0){
+ print_info("System files:");
+ for (size_t i=0; i<systemFiles.size(); i++) {
+ printf(" %s\n", systemFiles[i].c_str());
+ }
+ }
+ if (installApks.size() > 0){
+ print_info("APKs to install:");
+ for (size_t i=0; i<installApks.size(); i++) {
+ printf(" %s\n", installApks[i].file.filename.c_str());
+ }
+ }
+
//
// Build
//
@@ -798,7 +814,8 @@ run_phases(vector<Target*> targets, const Options& options)
for (size_t j=0; j<target->module.installed.size(); j++) {
string filename = target->module.installed[j];
- if (!ends_with(filename, ".apk")) {
+ // Apk in the data partition
+ if (!starts_with(filename, dataPath) || !ends_with(filename, ".apk")) {
continue;
}
@@ -1004,13 +1021,16 @@ run_phases(vector<Target*> targets, const Options& options)
void
run_tab_completion(const string& word)
{
- const string buildTop = get_required_env("ANDROID_BUILD_TOP", true);
+ const string buildTop = get_required_env("ANDROID_BUILD_TOP", false);
const string buildProduct = get_required_env("TARGET_PRODUCT", false);
+ const string buildVariant = get_required_env("TARGET_BUILD_VARIANT", false);
+ const string buildType = get_required_env("TARGET_BUILD_TYPE", false);
const string buildOut = get_out_dir();
-
chdir_or_exit(buildTop.c_str());
- string buildDevice = sniff_device_name(buildOut, buildProduct);
+ BuildVars buildVars(buildOut, buildProduct, buildVariant, buildType);
+
+ string buildDevice = buildVars.GetBuildVar("TARGET_DEVICE", false);
map<string,Module> modules;
read_modules(buildOut, buildDevice, &modules, true);
diff --git a/tools/bit/make.cpp b/tools/bit/make.cpp
index 5a9ab22719cb..627091321b2e 100644
--- a/tools/bit/make.cpp
+++ b/tools/bit/make.cpp
@@ -21,6 +21,7 @@
#include "util.h"
#include <json/reader.h>
+#include <json/writer.h>
#include <json/value.h>
#include <fstream>
@@ -34,22 +35,118 @@
using namespace std;
-map<string,string> g_buildVars;
+static bool
+map_contains(const map<string,string>& m, const string& k, const string& v) {
+ map<string,string>::const_iterator it = m.find(k);
+ if (it == m.end()) {
+ return false;
+ }
+ return it->second == v;
+}
+
+static string
+make_cache_filename(const string& outDir)
+{
+ string filename(outDir);
+ return filename + "/.bit_cache";
+}
+
+BuildVars::BuildVars(const string& outDir, const string& buildProduct,
+ const string& buildVariant, const string& buildType)
+ :m_filename(),
+ m_cache()
+{
+ m_cache["TARGET_PRODUCT"] = buildProduct;
+ m_cache["TARGET_BUILD_VARIANT"] = buildVariant;
+ m_cache["TARGET_BUILD_TYPE"] = buildType;
+
+ // If we have any problems reading the file, that's ok, just do
+ // uncached calls to make / soong.
+
+ if (outDir == "") {
+ return;
+ }
+
+
+ m_filename = make_cache_filename(outDir);
+
+ std::ifstream stream(m_filename, std::ifstream::binary);
+
+ if (stream.fail()) {
+ return;
+ }
+
+ Json::Value json;
+ Json::Reader reader;
+ if (!reader.parse(stream, json)) {
+ return;
+ }
+
+ if (!json.isObject()) {
+ return;
+ }
+
+ map<string,string> cache;
+
+ vector<string> names = json.getMemberNames();
+ const int N = names.size();
+ for (int i=0; i<N; i++) {
+ const string& name = names[i];
+ const Json::Value& value = json[name];
+ if (!value.isString()) {
+ continue;
+ }
+ cache[name] = value.asString();
+ }
+
+ // If all of the base variables match, then we can use this cache. Otherwise, use our
+ // base one. The next time someone reads a value, the new one, with our base varaibles
+ // will be saved.
+ if (map_contains(cache, "TARGET_PRODUCT", buildProduct)
+ && map_contains(cache, "TARGET_BUILD_VARIANT", buildVariant)
+ && map_contains(cache, "TARGET_BUILD_TYPE", buildType)) {
+ m_cache = cache;
+ }
+}
+
+BuildVars::~BuildVars()
+{
+}
+
+void
+BuildVars::save()
+{
+ if (m_filename == "") {
+ return;
+ }
+
+ Json::StyledStreamWriter writer(" ");
+
+ Json::Value json(Json::objectValue);
+
+ for (map<string,string>::const_iterator it = m_cache.begin(); it != m_cache.end(); it++) {
+ json[it->first] = it->second;
+ }
+
+ std::ofstream stream(m_filename, std::ofstream::binary);
+ writer.write(stream, json);
+}
string
-get_build_var(const string& name, bool quiet)
+BuildVars::GetBuildVar(const string& name, bool quiet)
{
int err;
- map<string,string>::iterator it = g_buildVars.find(name);
- if (it == g_buildVars.end()) {
+ map<string,string>::iterator it = m_cache.find(name);
+ if (it == m_cache.end()) {
Command cmd("build/soong/soong_ui.bash");
cmd.AddArg("--dumpvar-mode");
cmd.AddArg(name);
string output = trim(get_command_output(cmd, &err, quiet));
if (err == 0) {
- g_buildVars[name] = output;
+ m_cache[name] = output;
+ save();
return output;
} else {
return string();
@@ -59,38 +156,6 @@ get_build_var(const string& name, bool quiet)
}
}
-string
-sniff_device_name(const string& buildOut, const string& product)
-{
- string match("ro.build.product=" + product);
-
- string base(buildOut + "/target/product");
- DIR* dir = opendir(base.c_str());
- if (dir == NULL) {
- return string();
- }
-
- dirent* entry;
- while ((entry = readdir(dir)) != NULL) {
- if (entry->d_name[0] == '.') {
- continue;
- }
- if (entry->d_type == DT_DIR) {
- string filename(base + "/" + entry->d_name + "/system/build.prop");
- vector<string> lines;
- split_lines(&lines, read_file(filename));
- for (size_t i=0; i<lines.size(); i++) {
- if (lines[i] == match) {
- return entry->d_name;
- }
- }
- }
- }
-
- closedir(dir);
- return string();
-}
-
void
json_error(const string& filename, const char* error, bool quiet)
{
diff --git a/tools/bit/make.h b/tools/bit/make.h
index 1c9504d62d46..db0b69f88a0e 100644
--- a/tools/bit/make.h
+++ b/tools/bit/make.h
@@ -31,16 +31,26 @@ struct Module
vector<string> installed;
};
-string get_build_var(const string& name, bool quiet);
-
/**
- * Poke around in the out directory and try to find a device name that matches
- * our product. This is faster than running get_build_var and good enough for
- * tab completion.
- *
- * Returns the empty string if we can't find one.
+ * Class to encapsulate getting build variables. Caches the
+ * results if possible.
*/
-string sniff_device_name(const string& buildOut, const string& product);
+class BuildVars
+{
+public:
+ BuildVars(const string& outDir, const string& buildProduct,
+ const string& buildVariant, const string& buildType);
+ ~BuildVars();
+
+ string GetBuildVar(const string& name, bool quiet);
+
+private:
+ void save();
+
+ string m_filename;
+
+ map<string,string> m_cache;
+};
void read_modules(const string& buildOut, const string& buildDevice,
map<string,Module>* modules, bool quiet);
diff --git a/tools/bit/print.cpp b/tools/bit/print.cpp
index 790e0b4b227e..35feda11ec29 100644
--- a/tools/bit/print.cpp
+++ b/tools/bit/print.cpp
@@ -116,6 +116,20 @@ print_warning(const char* format, ...)
}
void
+print_info(const char* format, ...)
+{
+ fputs(g_escapeBold, stdout);
+
+ va_list args;
+ va_start(args, format);
+ vfprintf(stdout, format, args);
+ va_end(args);
+
+ fputs(g_escapeEndColor, stdout);
+ fputc('\n', stdout);
+}
+
+void
print_one_line(const char* format, ...)
{
if (g_stdoutIsTty) {
diff --git a/tools/bit/print.h b/tools/bit/print.h
index b6c3e9aa27fa..db6cf5f65cf8 100644
--- a/tools/bit/print.h
+++ b/tools/bit/print.h
@@ -33,6 +33,7 @@ void print_status(const char* format, ...);
void print_command(const Command& command);
void print_error(const char* format, ...);
void print_warning(const char* format, ...);
+void print_info(const char* format, ...);
void print_one_line(const char* format, ...);
void check_error(int err);