diff options
57 files changed, 1095 insertions, 1533 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp index 9f48bf475eb2..55f5436eed90 100644 --- a/AconfigFlags.bp +++ b/AconfigFlags.bp @@ -18,8 +18,11 @@ java_defaults { // Add java_aconfig_libraries to here to add them to the core framework srcs: [ + ":android.os.flags-aconfig-java{.generated_srcjars}", + ":android.security.flags-aconfig-java{.generated_srcjars}", ":com.android.hardware.camera2-aconfig-java{.generated_srcjars}", ":com.android.window.flags.window-aconfig-java{.generated_srcjars}", + ":com.android.hardware.input-aconfig-java{.generated_srcjars}", ":com.android.text.flags-aconfig-java{.generated_srcjars}", ], // Add aconfig-annotations-lib as a dependency for the optimization @@ -60,6 +63,19 @@ java_aconfig_library { defaults: ["framework-minus-apex-aconfig-java-defaults"], } +// Input +aconfig_declarations { + name: "com.android.hardware.input.input-aconfig", + package: "com.android.hardware.input", + srcs: ["core/java/android/hardware/input/*.aconfig"], +} + +java_aconfig_library { + name: "com.android.hardware.input-aconfig-java", + aconfig_declarations: "com.android.hardware.input.input-aconfig", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} + // Text aconfig_declarations { name: "com.android.text.flags-aconfig", @@ -72,3 +88,37 @@ java_aconfig_library { aconfig_declarations: "com.android.text.flags-aconfig", defaults: ["framework-minus-apex-aconfig-java-defaults"], } + +// OS +aconfig_declarations { + name: "android.os.flags-aconfig", + package: "android.os", + srcs: ["core/java/android/os/*.aconfig"], +} + +java_aconfig_library { + name: "android.os.flags-aconfig-java", + aconfig_declarations: "android.os.flags-aconfig", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} + +// Security +aconfig_declarations { + name: "android.security.flags-aconfig", + package: "android.security", + srcs: ["core/java/android/security/*.aconfig"], +} + +java_aconfig_library { + name: "android.security.flags-aconfig-java", + aconfig_declarations: "android.security.flags-aconfig", + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} + +java_aconfig_library { + name: "android.security.flags-aconfig-java-host", + aconfig_declarations: "android.security.flags-aconfig", + host_supported: true, + test: true, + defaults: ["framework-minus-apex-aconfig-java-defaults"], +} @@ -28,7 +28,7 @@ per-file */TEST_MAPPING = * # Support bulk translation updates per-file */res*/values*/*.xml = byi@google.com, delphij@google.com -per-file **.bp,**.mk = hansson@google.com, joeo@google.com +per-file **.bp,**.mk = hansson@google.com, joeo@google.com, lamontjones@google.com per-file TestProtoLibraries.bp = file:platform/platform_testing:/libraries/health/OWNERS per-file TestProtoLibraries.bp = file:platform/tools/tradefederation:/OWNERS diff --git a/cmds/idmap2/libidmap2/CommandLineOptions.cpp b/cmds/idmap2/libidmap2/CommandLineOptions.cpp index 8129d99650f7..b1edc1891541 100644 --- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp +++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp @@ -20,6 +20,7 @@ #include <cassert> #include <iomanip> #include <iostream> +#include <iterator> #include <memory> #include <set> #include <sstream> diff --git a/core/java/Android.bp b/core/java/Android.bp index 5d7d7ba2379c..da6a6d46c132 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -9,6 +9,11 @@ package { default_applicable_licenses: ["frameworks_base_license"], } +aidl_library { + name: "HardwareBuffer_aidl", + hdrs: ["android/hardware/HardwareBuffer.aidl"], +} + filegroup { name: "framework-core-sources", srcs: [ diff --git a/core/java/android/app/trust/ITrustListener.aidl b/core/java/android/app/trust/ITrustListener.aidl index e4ac01195bcb..8d4478493b13 100644 --- a/core/java/android/app/trust/ITrustListener.aidl +++ b/core/java/android/app/trust/ITrustListener.aidl @@ -24,6 +24,7 @@ import java.util.List; * {@hide} */ oneway interface ITrustListener { + void onEnabledTrustAgentsChanged(int userId); void onTrustChanged(boolean enabled, boolean newlyUnlocked, int userId, int flags, in List<String> trustGrantedMessages); void onTrustManagedChanged(boolean managed, int userId); diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java index 62f755d0268c..3552ce0e5889 100644 --- a/core/java/android/app/trust/TrustManager.java +++ b/core/java/android/app/trust/TrustManager.java @@ -43,6 +43,7 @@ public class TrustManager { private static final int MSG_TRUST_CHANGED = 1; private static final int MSG_TRUST_MANAGED_CHANGED = 2; private static final int MSG_TRUST_ERROR = 3; + private static final int MSG_ENABLED_TRUST_AGENTS_CHANGED = 4; private static final String TAG = "TrustManager"; private static final String DATA_FLAGS = "initiatedByUser"; @@ -187,6 +188,13 @@ public class TrustManager { } @Override + public void onEnabledTrustAgentsChanged(int userId) { + final Message m = mHandler.obtainMessage(MSG_ENABLED_TRUST_AGENTS_CHANGED, + userId, 0, trustListener); + m.sendToTarget(); + } + + @Override public void onTrustManagedChanged(boolean managed, int userId) { mHandler.obtainMessage(MSG_TRUST_MANAGED_CHANGED, (managed ? 1 : 0), userId, trustListener).sendToTarget(); @@ -283,6 +291,10 @@ public class TrustManager { case MSG_TRUST_ERROR: final CharSequence message = msg.peekData().getCharSequence(DATA_MESSAGE); ((TrustListener) msg.obj).onTrustError(message); + break; + case MSG_ENABLED_TRUST_AGENTS_CHANGED: + ((TrustListener) msg.obj).onEnabledTrustAgentsChanged(msg.arg1); + break; } } }; @@ -316,5 +328,10 @@ public class TrustManager { * @param message A message that should be displayed on the UI. */ void onTrustError(CharSequence message); + + /** + * Reports that the enabled trust agents for the specified user has changed. + */ + void onEnabledTrustAgentsChanged(int userId); } } diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig new file mode 100644 index 000000000000..ebfe66f51bbc --- /dev/null +++ b/core/java/android/hardware/input/input_framework.aconfig @@ -0,0 +1,19 @@ +package: "com.android.hardware.input" + +# Project link: https://gantry.corp.google.com/projects/android_platform_input_native/changes + +flag { + namespace: "input_native" + name: "keyboard_layout_preview_flag" + description: "Controls whether a preview will be shown in Settings when selecting a physical keyboard layout" + bug: "293579375" +} + + +flag { + namespace: "input_native" + name: "keyboard_a11y_sticky_keys_flag" + description: "Controls if the sticky keys accessibility feature for physical keyboard is available to the user" + bug: "294546335" +} + diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig new file mode 100644 index 000000000000..851aa6dce560 --- /dev/null +++ b/core/java/android/os/flags.aconfig @@ -0,0 +1,8 @@ +package: "android.os" + +flag { + name: "disallow_cellular_null_ciphers_restriction" + namespace: "cellular_security" + description: "Guards a new UserManager user restriction that admins can use to require cellular encryption on their managed devices." + bug: "276752881" +} diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig new file mode 100644 index 000000000000..b6c2b83f0daa --- /dev/null +++ b/core/java/android/security/flags.aconfig @@ -0,0 +1,15 @@ +package: "android.security" + +flag { + name: "fsverity_api" + namespace: "hardware_backed_security" + description: "Feature flag for fs-verity API" + bug: "285185747" +} + +flag { + name: "fix_unlocked_device_required_keys" + namespace: "hardware_backed_security" + description: "Fix bugs in behavior of UnlockedDeviceRequired keystore keys" + bug: "296464083" +} diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 6182253ffe39..11e43dd4507a 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -2434,6 +2434,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #getId() */ @IdRes + @ViewDebug.ExportedProperty(resolveId = true) int mID = NO_ID; /** The ID of this view for autofill purposes. @@ -4240,6 +4241,71 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * This view's request for the visibility of the status bar. * @hide */ + @ViewDebug.ExportedProperty(flagMapping = { + @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, + equals = SYSTEM_UI_FLAG_LOW_PROFILE, + name = "LOW_PROFILE"), + @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, + equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, + name = "HIDE_NAVIGATION"), + @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_FULLSCREEN, + equals = SYSTEM_UI_FLAG_FULLSCREEN, + name = "FULLSCREEN"), + @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_STABLE, + equals = SYSTEM_UI_FLAG_LAYOUT_STABLE, + name = "LAYOUT_STABLE"), + @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, + equals = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, + name = "LAYOUT_HIDE_NAVIGATION"), + @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, + equals = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, + name = "LAYOUT_FULLSCREEN"), + @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE, + equals = SYSTEM_UI_FLAG_IMMERSIVE, + name = "IMMERSIVE"), + @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, + equals = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, + name = "IMMERSIVE_STICKY"), + @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, + equals = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, + name = "LIGHT_STATUS_BAR"), + @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, + equals = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, + name = "LIGHT_NAVIGATION_BAR"), + @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_EXPAND, + equals = STATUS_BAR_DISABLE_EXPAND, + name = "STATUS_BAR_DISABLE_EXPAND"), + @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, + equals = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, + name = "STATUS_BAR_DISABLE_NOTIFICATION_ICONS"), + @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, + equals = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, + name = "STATUS_BAR_DISABLE_NOTIFICATION_ALERTS"), + @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, + equals = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, + name = "STATUS_BAR_DISABLE_NOTIFICATION_TICKER"), + @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SYSTEM_INFO, + equals = STATUS_BAR_DISABLE_SYSTEM_INFO, + name = "STATUS_BAR_DISABLE_SYSTEM_INFO"), + @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_HOME, + equals = STATUS_BAR_DISABLE_HOME, + name = "STATUS_BAR_DISABLE_HOME"), + @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_BACK, + equals = STATUS_BAR_DISABLE_BACK, + name = "STATUS_BAR_DISABLE_BACK"), + @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_CLOCK, + equals = STATUS_BAR_DISABLE_CLOCK, + name = "STATUS_BAR_DISABLE_CLOCK"), + @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_RECENT, + equals = STATUS_BAR_DISABLE_RECENT, + name = "STATUS_BAR_DISABLE_RECENT"), + @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH, + equals = STATUS_BAR_DISABLE_SEARCH, + name = "STATUS_BAR_DISABLE_SEARCH"), + @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, + equals = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, + name = "STATUS_BAR_DISABLE_ONGOING_CALL_CHIP") + }, formatToHexString = true) @SystemUiVisibility int mSystemUiVisibility; @@ -4358,6 +4424,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * to the left edge of this view. * {@hide} */ + @ViewDebug.ExportedProperty(category = "layout") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected int mLeft; /** @@ -4365,6 +4432,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * to the right edge of this view. * {@hide} */ + @ViewDebug.ExportedProperty(category = "layout") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected int mRight; /** @@ -4372,6 +4440,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * to the top edge of this view. * {@hide} */ + @ViewDebug.ExportedProperty(category = "layout") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected int mTop; /** @@ -4379,6 +4448,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * to the bottom edge of this view. * {@hide} */ + @ViewDebug.ExportedProperty(category = "layout") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected int mBottom; @@ -4389,6 +4459,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * accessing these directly. * {@hide} */ + @ViewDebug.ExportedProperty(category = "scrolling") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected int mScrollX; /** @@ -4398,6 +4469,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * accessing these directly. * {@hide} */ + @ViewDebug.ExportedProperty(category = "scrolling") @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) protected int mScrollY; @@ -4406,6 +4478,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * pixels between the left edge of this view and the left edge of its content. * {@hide} */ + @ViewDebug.ExportedProperty(category = "padding") @UnsupportedAppUsage protected int mPaddingLeft = 0; /** @@ -4413,6 +4486,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * pixels between the right edge of this view and the right edge of its content. * {@hide} */ + @ViewDebug.ExportedProperty(category = "padding") @UnsupportedAppUsage protected int mPaddingRight = 0; /** @@ -4420,6 +4494,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * pixels between the top edge of this view and the top edge of its content. * {@hide} */ + @ViewDebug.ExportedProperty(category = "padding") @UnsupportedAppUsage protected int mPaddingTop; /** @@ -4427,6 +4502,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * pixels between the bottom edge of this view and the bottom edge of its content. * {@hide} */ + @ViewDebug.ExportedProperty(category = "padding") @UnsupportedAppUsage protected int mPaddingBottom; @@ -17121,7 +17197,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return The left edge of the displayed part of your view, in pixels. */ @InspectableProperty - @ViewDebug.ExportedProperty(category = "scrolling") public final int getScrollX() { return mScrollX; } @@ -17134,7 +17209,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return The top edge of the displayed part of your view, in pixels. */ @InspectableProperty - @ViewDebug.ExportedProperty(category = "scrolling") public final int getScrollY() { return mScrollY; } @@ -17925,7 +17999,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return The top of this view, in pixels. */ @ViewDebug.CapturedViewProperty - @ViewDebug.ExportedProperty(category = "layout") public final int getTop() { return mTop; } @@ -17985,7 +18058,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return The bottom of this view, in pixels. */ @ViewDebug.CapturedViewProperty - @ViewDebug.ExportedProperty(category = "layout") public final int getBottom() { return mBottom; } @@ -18051,7 +18123,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return The left edge of this view, in pixels. */ @ViewDebug.CapturedViewProperty - @ViewDebug.ExportedProperty(category = "layout") public final int getLeft() { return mLeft; } @@ -18111,7 +18182,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return The right edge of this view, in pixels. */ @ViewDebug.CapturedViewProperty - @ViewDebug.ExportedProperty(category = "layout") public final int getRight() { return mRight; } @@ -25320,7 +25390,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return the top padding in pixels */ @InspectableProperty - @ViewDebug.ExportedProperty(category = "padding") public int getPaddingTop() { return mPaddingTop; } @@ -25333,7 +25402,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return the bottom padding in pixels */ @InspectableProperty - @ViewDebug.ExportedProperty(category = "padding") public int getPaddingBottom() { return mPaddingBottom; } @@ -25346,7 +25414,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return the left padding in pixels */ @InspectableProperty - @ViewDebug.ExportedProperty(category = "padding") public int getPaddingLeft() { if (!isPaddingResolved()) { resolvePadding(); @@ -25377,7 +25444,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return the right padding in pixels */ @InspectableProperty - @ViewDebug.ExportedProperty(category = "padding") public int getPaddingRight() { if (!isPaddingResolved()) { resolvePadding(); @@ -26063,7 +26129,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @IdRes @ViewDebug.CapturedViewProperty - @ViewDebug.ExportedProperty(resolveId = true) @InspectableProperty public int getId() { return mID; @@ -27026,71 +27091,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} * instead. */ - @ViewDebug.ExportedProperty(flagMapping = { - @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, - equals = SYSTEM_UI_FLAG_LOW_PROFILE, - name = "LOW_PROFILE"), - @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, - equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, - name = "HIDE_NAVIGATION"), - @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_FULLSCREEN, - equals = SYSTEM_UI_FLAG_FULLSCREEN, - name = "FULLSCREEN"), - @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_STABLE, - equals = SYSTEM_UI_FLAG_LAYOUT_STABLE, - name = "LAYOUT_STABLE"), - @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, - equals = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, - name = "LAYOUT_HIDE_NAVIGATION"), - @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, - equals = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, - name = "LAYOUT_FULLSCREEN"), - @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE, - equals = SYSTEM_UI_FLAG_IMMERSIVE, - name = "IMMERSIVE"), - @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, - equals = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, - name = "IMMERSIVE_STICKY"), - @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, - equals = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, - name = "LIGHT_STATUS_BAR"), - @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, - equals = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, - name = "LIGHT_NAVIGATION_BAR"), - @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_EXPAND, - equals = STATUS_BAR_DISABLE_EXPAND, - name = "STATUS_BAR_DISABLE_EXPAND"), - @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, - equals = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, - name = "STATUS_BAR_DISABLE_NOTIFICATION_ICONS"), - @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, - equals = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, - name = "STATUS_BAR_DISABLE_NOTIFICATION_ALERTS"), - @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, - equals = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, - name = "STATUS_BAR_DISABLE_NOTIFICATION_TICKER"), - @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SYSTEM_INFO, - equals = STATUS_BAR_DISABLE_SYSTEM_INFO, - name = "STATUS_BAR_DISABLE_SYSTEM_INFO"), - @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_HOME, - equals = STATUS_BAR_DISABLE_HOME, - name = "STATUS_BAR_DISABLE_HOME"), - @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_BACK, - equals = STATUS_BAR_DISABLE_BACK, - name = "STATUS_BAR_DISABLE_BACK"), - @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_CLOCK, - equals = STATUS_BAR_DISABLE_CLOCK, - name = "STATUS_BAR_DISABLE_CLOCK"), - @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_RECENT, - equals = STATUS_BAR_DISABLE_RECENT, - name = "STATUS_BAR_DISABLE_RECENT"), - @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH, - equals = STATUS_BAR_DISABLE_SEARCH, - name = "STATUS_BAR_DISABLE_SEARCH"), - @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, - equals = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, - name = "STATUS_BAR_DISABLE_ONGOING_CALL_CHIP") - }, formatToHexString = true) @Deprecated public int getSystemUiVisibility() { return mSystemUiVisibility; diff --git a/core/java/com/android/internal/util/FileRotator.java b/core/java/com/android/internal/util/FileRotator.java index 5bc48c5172f0..c9d9926ba75a 100644 --- a/core/java/com/android/internal/util/FileRotator.java +++ b/core/java/com/android/internal/util/FileRotator.java @@ -19,6 +19,9 @@ package com.android.internal.util; import android.annotation.NonNull; import android.os.FileUtils; import android.util.Log; +import android.util.Pair; + +import libcore.io.IoUtils; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -28,12 +31,12 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Comparator; import java.util.Objects; +import java.util.TreeSet; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import libcore.io.IoUtils; - /** * Utility that rotates files over time, similar to {@code logrotate}. There is * a single "active" file, which is periodically rotated into historical files, @@ -302,17 +305,24 @@ public class FileRotator { public void readMatching(Reader reader, long matchStartMillis, long matchEndMillis) throws IOException { final FileInfo info = new FileInfo(mPrefix); + final TreeSet<Pair<Long, String>> readSet = new TreeSet<>( + Comparator.comparingLong(o -> o.first)); for (String name : mBasePath.list()) { if (!info.parse(name)) continue; - // read file when it overlaps + // Add file to set when it overlaps. if (info.startMillis <= matchEndMillis && matchStartMillis <= info.endMillis) { - if (LOGD) Log.d(TAG, "reading matching " + name); - - final File file = new File(mBasePath, name); - readFile(file, reader); + readSet.add(new Pair(info.startMillis, name)); } } + + // Read files in ascending order of start timestamp. + for (Pair<Long, String> pair : readSet) { + final String name = pair.second; + if (LOGD) Log.d(TAG, "reading matching " + name); + final File file = new File(mBasePath, name); + readFile(file, reader); + } } /** diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index bbaea0a45798..418000f60ca1 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -1806,15 +1806,10 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, if (!is_system_server && getuid() == 0) { const int rc = createProcessGroup(uid, getpid()); if (rc != 0) { - if (rc == -ESRCH) { - // If process is dead, treat this as a non-fatal error - ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc)); - } else { - fail_fn(rc == -EROFS ? CREATE_ERROR("createProcessGroup failed, kernel missing " - "CONFIG_CGROUP_CPUACCT?") - : CREATE_ERROR("createProcessGroup(%d, %d) failed: %s", uid, - /* pid= */ 0, strerror(-rc))); - } + fail_fn(rc == -EROFS ? CREATE_ERROR("createProcessGroup failed, kernel missing " + "CONFIG_CGROUP_CPUACCT?") + : CREATE_ERROR("createProcessGroup(%d, %d) failed: %s", uid, + /* pid= */ 0, strerror(-rc))); } } diff --git a/core/tests/coretests/src/android/hardware/input/InputFlagsTest.java b/core/tests/coretests/src/android/hardware/input/InputFlagsTest.java new file mode 100644 index 000000000000..5aeab42eaaea --- /dev/null +++ b/core/tests/coretests/src/android/hardware/input/InputFlagsTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2023 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.hardware.input; + +import static com.android.hardware.input.Flags.keyboardA11yStickyKeysFlag; +import static com.android.hardware.input.Flags.keyboardLayoutPreviewFlag; + +import android.platform.test.annotations.Presubmit; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests for {@link com.android.hardware.input.Flags} + * + * Build/Install/Run: + * atest FrameworksCoreTests:InputFlagsTest + */ +@RunWith(AndroidJUnit4.class) +@SmallTest +@Presubmit +public class InputFlagsTest { + + /** + * Test that the flags work + */ + @Test + public void testFlags() { + // No crash when accessing the flag. + keyboardLayoutPreviewFlag(); + keyboardA11yStickyKeysFlag(); + } +} + diff --git a/core/tests/utiltests/src/com/android/internal/util/FileRotatorTest.java b/core/tests/utiltests/src/com/android/internal/util/FileRotatorTest.java index 952721320c90..73e47e1635b4 100644 --- a/core/tests/utiltests/src/com/android/internal/util/FileRotatorTest.java +++ b/core/tests/utiltests/src/com/android/internal/util/FileRotatorTest.java @@ -366,6 +366,16 @@ public class FileRotatorTest extends AndroidTestCase { assertReadAll(rotate, "bar"); } + public void testReadSorted() throws Exception { + write("rotator.1024-2048", "2"); + write("rotator.2048-4096", "3"); + write("rotator.512-1024", "1"); + + final FileRotator rotate = new FileRotator( + mBasePath, PREFIX, SECOND_IN_MILLIS, SECOND_IN_MILLIS); + assertReadAll(rotate, "1", "2", "3"); + } + public void testFileSystemInaccessible() throws Exception { File inaccessibleDir = null; String dirPath = getContext().getFilesDir() + File.separator + "inaccessible"; @@ -422,16 +432,7 @@ public class FileRotatorTest extends AndroidTestCase { } public void assertRead(String... expected) { - assertEquals(expected.length, mActual.size()); - - final ArrayList<String> actualCopy = new ArrayList<String>(mActual); - for (String value : expected) { - if (!actualCopy.remove(value)) { - final String expectedString = Arrays.toString(expected); - final String actualString = Arrays.toString(mActual.toArray()); - fail("expected: " + expectedString + " but was: " + actualString); - } - } + assertEquals(Arrays.asList(expected), mActual); } } } diff --git a/data/keyboards/qwerty.idc b/data/keyboards/qwerty.idc deleted file mode 100644 index 375d78576548..000000000000 --- a/data/keyboards/qwerty.idc +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (C) 2010 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. - -# -# Emulator keyboard configuration file #1. -# - -touch.deviceType = touchScreen -touch.orientationAware = 1 - -keyboard.layout = qwerty -keyboard.characterMap = qwerty -keyboard.orientationAware = 1 -keyboard.builtIn = 1 - -cursor.mode = navigation -cursor.orientationAware = 1 diff --git a/data/keyboards/qwerty.kcm b/data/keyboards/qwerty.kcm deleted file mode 100644 index f3e152418a4c..000000000000 --- a/data/keyboards/qwerty.kcm +++ /dev/null @@ -1,508 +0,0 @@ -# Copyright (C) 2010 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. - -# -# Emulator keyboard character map #1. -# -# This file is no longer used as the platform's default keyboard character map. -# Refer to Generic.kcm and Virtual.kcm instead. -# - -type ALPHA - -key A { - label: 'A' - number: '2' - base: 'a' - shift, capslock: 'A' - alt: '#' - shift+alt, capslock+alt: none -} - -key B { - label: 'B' - number: '2' - base: 'b' - shift, capslock: 'B' - alt: '<' - shift+alt, capslock+alt: none -} - -key C { - label: 'C' - number: '2' - base: 'c' - shift, capslock: 'C' - alt: '9' - shift+alt, capslock+alt: '\u00e7' -} - -key D { - label: 'D' - number: '3' - base: 'd' - shift, capslock: 'D' - alt: '5' - shift+alt, capslock+alt: none -} - -key E { - label: 'E' - number: '3' - base: 'e' - shift, capslock: 'E' - alt: '2' - shift+alt, capslock+alt: '\u0301' -} - -key F { - label: 'F' - number: '3' - base: 'f' - shift, capslock: 'F' - alt: '6' - shift+alt, capslock+alt: '\u00a5' -} - -key G { - label: 'G' - number: '4' - base: 'g' - shift, capslock: 'G' - alt: '-' - shift+alt, capslock+alt: '_' -} - -key H { - label: 'H' - number: '4' - base: 'h' - shift, capslock: 'H' - alt: '[' - shift+alt, capslock+alt: '{' -} - -key I { - label: 'I' - number: '4' - base: 'i' - shift, capslock: 'I' - alt: '$' - shift+alt, capslock+alt: '\u0302' -} - -key J { - label: 'J' - number: '5' - base: 'j' - shift, capslock: 'J' - alt: ']' - shift+alt, capslock+alt: '}' -} - -key K { - label: 'K' - number: '5' - base: 'k' - shift, capslock: 'K' - alt: '"' - shift+alt, capslock+alt: '~' -} - -key L { - label: 'L' - number: '5' - base: 'l' - shift, capslock: 'L' - alt: '\'' - shift+alt, capslock+alt: '`' -} - -key M { - label: 'M' - number: '6' - base: 'm' - shift, capslock: 'M' - alt: '!' - shift+alt, capslock+alt: none -} - -key N { - label: 'N' - number: '6' - base: 'n' - shift, capslock: 'N' - alt: '>' - shift+alt, capslock+alt: '\u0303' -} - -key O { - label: 'O' - number: '6' - base: 'o' - shift, capslock: 'O' - alt: '(' - shift+alt, capslock+alt: none -} - -key P { - label: 'P' - number: '7' - base: 'p' - shift, capslock: 'P' - alt: ')' - shift+alt, capslock+alt: none -} - -key Q { - label: 'Q' - number: '7' - base: 'q' - shift, capslock: 'Q' - alt: '*' - shift+alt, capslock+alt: '\u0300' -} - -key R { - label: 'R' - number: '7' - base: 'r' - shift, capslock: 'R' - alt: '3' - shift+alt, capslock+alt: '\u20ac' -} - -key S { - label: 'S' - number: '7' - base: 's' - shift, capslock: 'S' - alt: '4' - shift+alt, capslock+alt: '\u00df' -} - -key T { - label: 'T' - number: '8' - base: 't' - shift, capslock: 'T' - alt: '+' - shift+alt, capslock+alt: '\u00a3' -} - -key U { - label: 'U' - number: '8' - base: 'u' - shift, capslock: 'U' - alt: '&' - shift+alt, capslock+alt: '\u0308' -} - -key V { - label: 'V' - number: '8' - base: 'v' - shift, capslock: 'V' - alt: '=' - shift+alt, capslock+alt: '^' -} - -key W { - label: 'W' - number: '9' - base: 'w' - shift, capslock: 'W' - alt: '1' - shift+alt, capslock+alt: none -} - -key X { - label: 'X' - number: '9' - base: 'x' - shift, capslock: 'X' - alt: '8' - shift+alt, capslock+alt: '\uef00' -} - -key Y { - label: 'Y' - number: '9' - base: 'y' - shift, capslock: 'Y' - alt: '%' - shift+alt, capslock+alt: '\u00a1' -} - -key Z { - label: 'Z' - number: '9' - base: 'z' - shift, capslock: 'Z' - alt: '7' - shift+alt, capslock+alt: none -} - -key COMMA { - label: ',' - number: ',' - base: ',' - shift: ';' - alt: ';' - shift+alt: '|' -} - -key PERIOD { - label: '.' - number: '.' - base: '.' - shift: ':' - alt: ':' - shift+alt: '\u2026' -} - -key AT { - label: '@' - number: '0' - base: '@' - shift: '0' - alt: '0' - shift+alt: '\u2022' -} - -key SLASH { - label: '/' - number: '/' - base: '/' - shift: '?' - alt: '?' - shift+alt: '\\' -} - -key SPACE { - label: ' ' - number: ' ' - base: ' ' - shift: ' ' - alt: '\uef01' - shift+alt: '\uef01' -} - -key ENTER { - label: '\n' - number: '\n' - base: '\n' - shift: '\n' - alt: '\n' - shift+alt: '\n' -} - -key TAB { - label: '\t' - number: '\t' - base: '\t' - shift: '\t' - alt: '\t' - shift+alt: '\t' -} - -key 0 { - label: '0' - number: '0' - base: '0' - shift: ')' - alt: ')' - shift+alt: ')' -} - -key 1 { - label: '1' - number: '1' - base: '1' - shift: '!' - alt: '!' - shift+alt: '!' -} - -key 2 { - label: '2' - number: '2' - base: '2' - shift: '@' - alt: '@' - shift+alt: '@' -} - -key 3 { - label: '3' - number: '3' - base: '3' - shift: '#' - alt: '#' - shift+alt: '#' -} - -key 4 { - label: '4' - number: '4' - base: '4' - shift: '$' - alt: '$' - shift+alt: '$' -} - -key 5 { - label: '5' - number: '5' - base: '5' - shift: '%' - alt: '%' - shift+alt: '%' -} - -key 6 { - label: '6' - number: '6' - base: '6' - shift: '^' - alt: '^' - shift+alt: '^' -} - -key 7 { - label: '7' - number: '7' - base: '7' - shift: '&' - alt: '&' - shift+alt: '&' -} - -key 8 { - label: '8' - number: '8' - base: '8' - shift: '*' - alt: '*' - shift+alt: '*' -} - -key 9 { - label: '9' - number: '9' - base: '9' - shift: '(' - alt: '(' - shift+alt: '(' -} - -key GRAVE { - label: '`' - number: '`' - base: '`' - shift: '~' - alt: '`' - shift+alt: '~' -} - -key MINUS { - label: '-' - number: '-' - base: '-' - shift: '_' - alt: '-' - shift+alt: '_' -} - -key EQUALS { - label: '=' - number: '=' - base: '=' - shift: '+' - alt: '=' - shift+alt: '+' -} - -key LEFT_BRACKET { - label: '[' - number: '[' - base: '[' - shift: '{' - alt: '[' - shift+alt: '{' -} - -key RIGHT_BRACKET { - label: ']' - number: ']' - base: ']' - shift: '}' - alt: ']' - shift+alt: '}' -} - -key BACKSLASH { - label: '\\' - number: '\\' - base: '\\' - shift: '|' - alt: '\\' - shift+alt: '|' -} - -key SEMICOLON { - label: ';' - number: ';' - base: ';' - shift: ':' - alt: ';' - shift+alt: ':' -} - -key APOSTROPHE { - label: '\'' - number: '\'' - base: '\'' - shift: '"' - alt: '\'' - shift+alt: '"' -} - -key STAR { - label: '*' - number: '*' - base: '*' - shift: '*' - alt: '*' - shift+alt: '*' -} - -key POUND { - label: '#' - number: '#' - base: '#' - shift: '#' - alt: '#' - shift+alt: '#' -} - -key PLUS { - label: '+' - number: '+' - base: '+' - shift: '+' - alt: '+' - shift+alt: '+' -} diff --git a/data/keyboards/qwerty.kl b/data/keyboards/qwerty.kl deleted file mode 100644 index 2fd99abbb9fe..000000000000 --- a/data/keyboards/qwerty.kl +++ /dev/null @@ -1,131 +0,0 @@ -# Copyright (C) 2010 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. - -# -# Emulator keyboard layout #1. -# -# This file is no longer used as the platform's default keyboard layout. -# Refer to Generic.kl instead. -# - -key 399 GRAVE -key 2 1 -key 3 2 -key 4 3 -key 5 4 -key 6 5 -key 7 6 -key 8 7 -key 9 8 -key 10 9 -key 11 0 -key 158 BACK -key 230 SOFT_RIGHT -key 60 SOFT_LEFT -key 107 ENDCALL -key 62 ENDCALL -key 229 MENU -key 139 MENU -key 59 MENU -key 127 SEARCH -key 217 SEARCH -key 228 POUND -key 227 STAR -key 231 CALL -key 61 CALL -key 232 DPAD_CENTER -key 108 DPAD_DOWN -key 103 DPAD_UP -key 102 HOME -key 105 DPAD_LEFT -key 106 DPAD_RIGHT -key 115 VOLUME_UP -key 114 VOLUME_DOWN -key 116 POWER -key 212 CAMERA - -key 16 Q -key 17 W -key 18 E -key 19 R -key 20 T -key 21 Y -key 22 U -key 23 I -key 24 O -key 25 P -key 26 LEFT_BRACKET -key 27 RIGHT_BRACKET -key 43 BACKSLASH - -key 30 A -key 31 S -key 32 D -key 33 F -key 34 G -key 35 H -key 36 J -key 37 K -key 38 L -key 39 SEMICOLON -key 40 APOSTROPHE -key 14 DEL - -key 44 Z -key 45 X -key 46 C -key 47 V -key 48 B -key 49 N -key 50 M -key 51 COMMA -key 52 PERIOD -key 53 SLASH -key 28 ENTER - -key 56 ALT_LEFT -key 100 ALT_RIGHT -key 42 SHIFT_LEFT -key 54 SHIFT_RIGHT -key 15 TAB -key 57 SPACE -key 150 EXPLORER -key 155 ENVELOPE - -key 12 MINUS -key 13 EQUALS -key 215 AT - -# On an AT keyboard: ESC, F10 -key 1 BACK -key 68 MENU - -# App switch = Overview key -key 580 APP_SWITCH - -# Media control keys -key 160 MEDIA_CLOSE -key 161 MEDIA_EJECT -key 163 MEDIA_NEXT -key 164 MEDIA_PLAY_PAUSE -key 165 MEDIA_PREVIOUS -key 166 MEDIA_STOP -key 167 MEDIA_RECORD -key 168 MEDIA_REWIND - -key 142 SLEEP -key 581 STEM_PRIMARY -key 582 STEM_1 -key 583 STEM_2 -key 584 STEM_3 diff --git a/data/keyboards/qwerty2.idc b/data/keyboards/qwerty2.idc deleted file mode 100644 index 369205ea3f98..000000000000 --- a/data/keyboards/qwerty2.idc +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (C) 2010 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. - -# -# Emulator keyboard configuration file #2. -# - -touch.deviceType = touchScreen -touch.orientationAware = 1 - -keyboard.layout = qwerty -keyboard.characterMap = qwerty2 -keyboard.orientationAware = 1 -keyboard.builtIn = 1 - -cursor.mode = navigation -cursor.orientationAware = 1 diff --git a/data/keyboards/qwerty2.kcm b/data/keyboards/qwerty2.kcm deleted file mode 100644 index b981d835bdfb..000000000000 --- a/data/keyboards/qwerty2.kcm +++ /dev/null @@ -1,505 +0,0 @@ -# Copyright (C) 2010 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. - -# -# Emulator keyboard character map #2. -# - -type ALPHA - -key A { - label: 'A' - number: '2' - base: 'a' - shift, capslock: 'A' - alt: '\u00e1' - shift+alt, capslock+alt: '\u00c1' -} - -key B { - label: 'B' - number: '2' - base: 'b' - shift, capslock: 'B' - alt: 'b' - shift+alt, capslock+alt: 'B' -} - -key C { - label: 'C' - number: '2' - base: 'c' - shift, capslock: 'C' - alt: '\u00a9' - shift+alt, capslock+alt: '\u00a2' -} - -key D { - label: 'D' - number: '3' - base: 'd' - shift, capslock: 'D' - alt: '\u00f0' - shift+alt, capslock+alt: '\u00d0' -} - -key E { - label: 'E' - number: '3' - base: 'e' - shift, capslock: 'E' - alt: '\u00e9' - shift+alt, capslock+alt: '\u00c9' -} - -key F { - label: 'F' - number: '3' - base: 'f' - shift, capslock: 'F' - alt: '[' - shift+alt, capslock+alt: '[' -} - -key G { - label: 'G' - number: '4' - base: 'g' - shift, capslock: 'G' - alt: ']' - shift+alt, capslock+alt: ']' -} - -key H { - label: 'H' - number: '4' - base: 'h' - shift, capslock: 'H' - alt: '<' - shift+alt, capslock+alt: '<' -} - -key I { - label: 'I' - number: '4' - base: 'i' - shift, capslock: 'I' - alt: '\u00ed' - shift+alt, capslock+alt: '\u00cd' -} - -key J { - label: 'J' - number: '5' - base: 'j' - shift, capslock: 'J' - alt: '>' - shift+alt, capslock+alt: '>' -} - -key K { - label: 'K' - number: '5' - base: 'k' - shift, capslock: 'K' - alt: ';' - shift+alt, capslock+alt: '~' -} - -key L { - label: 'L' - number: '5' - base: 'l' - shift, capslock: 'L' - alt: '\u00f8' - shift+alt, capslock+alt: '\u00d8' -} - -key M { - label: 'M' - number: '6' - base: 'm' - shift, capslock: 'M' - alt: '\u00b5' - shift+alt, capslock+alt: none -} - -key N { - label: 'N' - number: '6' - base: 'n' - shift, capslock: 'N' - alt: '\u00f1' - shift+alt, capslock+alt: '\u00d1' -} - -key O { - label: 'O' - number: '6' - base: 'o' - shift, capslock: 'O' - alt: '\u00f3' - shift+alt, capslock+alt: '\u00d3' -} - -key P { - label: 'P' - number: '7' - base: 'p' - shift, capslock: 'P' - alt: '\u00f6' - shift+alt, capslock+alt: '\u00d6' -} - -key Q { - label: 'Q' - number: '7' - base: 'q' - shift, capslock: 'Q' - alt: '\u00e4' - shift+alt, capslock+alt: '\u00c4' -} - -key R { - label: 'R' - number: '7' - base: 'r' - shift, capslock: 'R' - alt: '\u00ae' - shift+alt, capslock+alt: 'R' -} - -key S { - label: 'S' - number: '7' - base: 's' - shift, capslock: 'S' - alt: '\u00df' - shift+alt, capslock+alt: '\u00a7' -} - -key T { - label: 'T' - number: '8' - base: 't' - shift, capslock: 'T' - alt: '\u00fe' - shift+alt, capslock+alt: '\u00de' -} - -key U { - label: 'U' - number: '8' - base: 'u' - shift, capslock: 'U' - alt: '\u00fa' - shift+alt, capslock+alt: '\u00da' -} - -key V { - label: 'V' - number: '8' - base: 'v' - shift, capslock: 'V' - alt: 'v' - shift+alt, capslock+alt: 'V' -} - -key W { - label: 'W' - number: '9' - base: 'w' - shift, capslock: 'W' - alt: '\u00e5' - shift+alt, capslock+alt: '\u00c5' -} - -key X { - label: 'X' - number: '9' - base: 'x' - shift, capslock: 'X' - alt: 'x' - shift+alt, capslock+alt: '\uef00' -} - -key Y { - label: 'Y' - number: '9' - base: 'y' - shift, capslock: 'Y' - alt: '\u00fc' - shift+alt, capslock+alt: '\u00dc' -} - -key Z { - label: 'Z' - number: '9' - base: 'z' - shift, capslock: 'Z' - alt: '\u00e6' - shift+alt, capslock+alt: '\u00c6' -} - -key COMMA { - label: ',' - number: ',' - base: ',' - shift: '<' - alt: '\u00e7' - shift+alt: '\u00c7' -} - -key PERIOD { - label: '.' - number: '.' - base: '.' - shift: '>' - alt: '.' - shift+alt: '\u2026' -} - -key AT { - label: '@' - number: '@' - base: '@' - shift: '@' - alt: '@' - shift+alt: '\u2022' -} - -key SLASH { - label: '/' - number: '/' - base: '/' - shift: '?' - alt: '\u00bf' - shift+alt: '?' -} - -key SPACE { - label: ' ' - number: ' ' - base: ' ' - shift: ' ' - alt: '\uef01' - shift+alt: '\uef01' -} - -key ENTER { - label: '\n' - number: '\n' - base: '\n' - shift: '\n' - alt: '\n' - shift+alt: '\n' -} - -key TAB { - label: '\t' - number: '\t' - base: '\t' - shift: '\t' - alt: '\t' - shift+alt: '\t' -} - -key 0 { - label: '0' - number: '0' - base: '0' - shift: ')' - alt: '\u02bc' - shift+alt: ')' -} - -key 1 { - label: '1' - number: '1' - base: '1' - shift: '!' - alt: '\u00a1' - shift+alt: '\u00b9' -} - -key 2 { - label: '2' - number: '2' - base: '2' - shift: '@' - alt: '\u00b2' - shift+alt: '@' -} - -key 3 { - label: '3' - number: '3' - base: '3' - shift: '#' - alt: '\u00b3' - shift+alt: '#' -} - -key 4 { - label: '4' - number: '4' - base: '4' - shift: '$' - alt: '\u00a4' - shift+alt: '\u00a3' -} - -key 5 { - label: '5' - number: '5' - base: '5' - shift: '%' - alt: '\u20ac' - shift+alt: '%' -} - -key 6 { - label: '6' - number: '6' - base: '6' - shift: '^' - alt: '\u00bc' - shift+alt: '\u0302' -} - -key 7 { - label: '7' - number: '7' - base: '7' - shift: '&' - alt: '\u00bd' - shift+alt: '&' -} - -key 8 { - label: '8' - number: '8' - base: '8' - shift: '*' - alt: '\u00be' - shift+alt: '*' -} - -key 9 { - label: '9' - number: '9' - base: '9' - shift: '(' - alt: '\u02bb' - shift+alt: '(' -} - -key GRAVE { - label: '`' - number: '`' - base: '`' - shift: '~' - alt: '\u0300' - shift+alt: '\u0303' -} - -key MINUS { - label: '-' - number: '-' - base: '-' - shift: '_' - alt: '\u00a5' - shift+alt: '_' -} - -key EQUALS { - label: '=' - number: '=' - base: '=' - shift: '+' - alt: '\u00d7' - shift+alt: '\u00f7' -} - -key LEFT_BRACKET { - label: '[' - number: '[' - base: '[' - shift: '{' - alt: '\u00ab' - shift+alt: '{' -} - -key RIGHT_BRACKET { - label: ']' - number: ']' - base: ']' - shift: '}' - alt: '\u00bb' - shift+alt: '}' -} - -key BACKSLASH { - label: '\\' - number: '\\' - base: '\\' - shift: '|' - alt: '\u00ac' - shift+alt: '\u00a6' -} - -key SEMICOLON { - label: ';' - number: ';' - base: ';' - shift: ':' - alt: '\u00b6' - shift+alt: '\u00b0' -} - -key APOSTROPHE { - label: '\'' - number: '\'' - base: '\'' - shift: '"' - alt: '\u0301' - shift+alt: '\u0308' -} - -key STAR { - label: '*' - number: '*' - base: '*' - shift: '*' - alt: '*' - shift+alt: '*' -} - -key POUND { - label: '#' - number: '#' - base: '#' - shift: '#' - alt: '#' - shift+alt: '#' -} - -key PLUS { - label: '+' - number: '+' - base: '+' - shift: '+' - alt: '+' - shift+alt: '+' -} diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index dc2185ea2f6c..daed277c7314 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -99,6 +99,13 @@ struct FindEntryResult { StringPoolRef entry_string_ref; }; +struct Theme::Entry { + uint32_t attr_res_id; + ApkAssetsCookie cookie; + uint32_t type_spec_flags; + Res_value value; +}; + AssetManager2::AssetManager2() { memset(&configuration_, 0, sizeof(configuration_)); } @@ -1411,13 +1418,6 @@ Theme::Theme(AssetManager2* asset_manager) : asset_manager_(asset_manager) { Theme::~Theme() = default; -struct Theme::Entry { - uint32_t attr_res_id; - ApkAssetsCookie cookie; - uint32_t type_spec_flags; - Res_value value; -}; - namespace { struct ThemeEntryKeyComparer { bool operator() (const Theme::Entry& entry, uint32_t attr_res_id) const noexcept { diff --git a/packages/CredentialManager/horologist/OWNERS b/packages/CredentialManager/horologist/OWNERS new file mode 100644 index 000000000000..b67932835b4a --- /dev/null +++ b/packages/CredentialManager/horologist/OWNERS @@ -0,0 +1,4 @@ +include /core/java/android/credentials/OWNERS + +shuanghao@google.com +gustavopagani@google.com diff --git a/packages/CredentialManager/shared/OWNERS b/packages/CredentialManager/shared/OWNERS new file mode 100644 index 000000000000..b67932835b4a --- /dev/null +++ b/packages/CredentialManager/shared/OWNERS @@ -0,0 +1,4 @@ +include /core/java/android/credentials/OWNERS + +shuanghao@google.com +gustavopagani@google.com diff --git a/packages/CredentialManager/wear/OWNERS b/packages/CredentialManager/wear/OWNERS new file mode 100644 index 000000000000..b67932835b4a --- /dev/null +++ b/packages/CredentialManager/wear/OWNERS @@ -0,0 +1,4 @@ +include /core/java/android/credentials/OWNERS + +shuanghao@google.com +gustavopagani@google.com diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS index 0cd8b455cc03..5b2409abc113 100644 --- a/packages/SystemUI/OWNERS +++ b/packages/SystemUI/OWNERS @@ -6,6 +6,7 @@ dsandler@android.com aaliomer@google.com aaronjli@google.com +achalke@google.com acul@google.com adamcohen@google.com aioana@google.com @@ -72,6 +73,7 @@ omarmt@google.com patmanning@google.com peanutbutter@google.com peskal@google.com +petrcermak@google.com pinyaoting@google.com pixel@google.com pomini@google.com @@ -83,14 +85,17 @@ santie@google.com shanh@google.com snoeberger@google.com steell@google.com +stevenckng@google.com stwu@google.com syeonlee@google.com sunnygoyal@google.com thiruram@google.com +tkachenkoi@google.com tracyzhou@google.com tsuji@google.com twickham@google.com vadimt@google.com +vanjan@google.com victortulias@google.com winsonc@google.com wleshner@google.com diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index a08f540bb1b1..6507488c73f5 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -549,6 +549,18 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab dispatchErrorMessage(message); } + @Override + public void onEnabledTrustAgentsChanged(int userId) { + Assert.isMainThread(); + + for (int i = 0; i < mCallbacks.size(); i++) { + KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); + if (cb != null) { + cb.onEnabledTrustAgentsChanged(userId); + } + } + } + private void handleSimSubscriptionInfoChanged() { Assert.isMainThread(); mLogger.v("onSubscriptionInfoChanged()"); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java index feff216310df..73940055c89f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java @@ -322,4 +322,9 @@ public class KeyguardUpdateMonitorCallback { * Called when keyguard is going away or not going away. */ public void onKeyguardGoingAway() { } + + /** + * Called when the enabled trust agents associated with the specified user. + */ + public void onEnabledTrustAgentsChanged(int userId) { } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt index d90f328719bb..e912053a85ca 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/TrustRepository.kt @@ -75,6 +75,8 @@ constructor( override fun onTrustError(message: CharSequence?) = Unit override fun onTrustManagedChanged(enabled: Boolean, userId: Int) = Unit + + override fun onEnabledTrustAgentsChanged(userId: Int) = Unit } trustManager.registerTrustListener(callback) logger.trustListenerRegistered() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java index f1269f2b012a..f4cf4eff8a7a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java @@ -452,5 +452,10 @@ public class KeyguardStateControllerImpl implements KeyguardStateController, Dum public void onBiometricsCleared() { update(false /* alwaysUpdate */); } + + @Override + public void onEnabledTrustAgentsChanged(int userId) { + update(false /* updateAlways */); + } } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index b1051af4ad15..417eb40eab54 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -144,6 +144,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; +import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; @@ -722,6 +723,18 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test + public void testOnEnabledTrustAgentsChangedCallback() { + final Random random = new Random(); + final int userId = random.nextInt(); + final KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class); + + mKeyguardUpdateMonitor.registerCallback(callback); + mKeyguardUpdateMonitor.onEnabledTrustAgentsChanged(userId); + + verify(callback).onEnabledTrustAgentsChanged(eq(userId)); + } + + @Test public void trustAgentHasTrust_fingerprintLockout() { // GIVEN user has trust mKeyguardUpdateMonitor.onTrustChanged(true, true, getCurrentUser(), 0, null); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java index 8f363efd9f51..d787ada90a73 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java @@ -31,18 +31,23 @@ import androidx.test.filters.SmallTest; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.keyguard.logging.KeyguardUpdateMonitorLogger; import com.android.systemui.SysuiTestCase; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; +import dagger.Lazy; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import dagger.Lazy; +import java.util.Random; + @SmallTest @TestableLooper.RunWithLooper @@ -169,4 +174,19 @@ public class KeyguardStateControllerTest extends SysuiTestCase { verify(callback).onKeyguardDismissAmountChanged(); } + @Test + public void testOnEnabledTrustAgentsChangedCallback() { + final Random random = new Random(); + final ArgumentCaptor<KeyguardUpdateMonitorCallback> updateCallbackCaptor = + ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class); + + verify(mKeyguardUpdateMonitor).registerCallback(updateCallbackCaptor.capture()); + final KeyguardStateController.Callback stateCallback = + mock(KeyguardStateController.Callback.class); + mKeyguardStateController.addCallback(stateCallback); + + when(mLockPatternUtils.isSecure(anyInt())).thenReturn(true); + updateCallbackCaptor.getValue().onEnabledTrustAgentsChanged(random.nextInt()); + verify(stateCallback).onUnlockedChanged(); + } } diff --git a/services/backup/backuplib/java/com/android/server/backup/TransportManager.java b/services/backup/backuplib/java/com/android/server/backup/TransportManager.java index 930f49e4d117..ff5f509fb11b 100644 --- a/services/backup/backuplib/java/com/android/server/backup/TransportManager.java +++ b/services/backup/backuplib/java/com/android/server/backup/TransportManager.java @@ -706,6 +706,9 @@ public class TransportManager { try { String transportName = transport.name(); String transportDirName = transport.transportDirName(); + if (transportName == null || transportDirName == null) { + return BackupManager.ERROR_TRANSPORT_INVALID; + } registerTransport(transportComponent, transport); // If registerTransport() hasn't thrown... Slog.d(TAG, "Transport " + transportString + " registered"); diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java index 846c2d9f3df7..a53d09678cd3 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java @@ -433,6 +433,11 @@ public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManage } @Override + public void onEnabledTrustAgentsChanged(int userId) { + + } + + @Override @NonNull public List<FingerprintSensorPropertiesInternal> getSensorProperties() { final List<FingerprintSensorPropertiesInternal> properties = new ArrayList<>(); diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index bfccd58b3f5d..53fbe8f37046 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -1741,6 +1741,7 @@ public class Vpn { .setBypassableVpn(bypassable) .setVpnRequiresValidation(mConfig.requiresInternetValidation) .setLocalRoutesExcludedForVpn(mConfig.excludeLocalRoutes) + .setLegacyExtraInfo("VPN:" + mPackage) .build(); capsBuilder.setOwnerUid(mOwnerUID); diff --git a/services/core/java/com/android/server/security/OWNERS b/services/core/java/com/android/server/security/OWNERS index f408d7c2efac..fa4bf228c683 100644 --- a/services/core/java/com/android/server/security/OWNERS +++ b/services/core/java/com/android/server/security/OWNERS @@ -4,3 +4,4 @@ include /core/java/android/security/OWNERS per-file *AttestationVerification* = file:/core/java/android/security/attestationverification/OWNERS per-file FileIntegrity*.java = victorhsieh@google.com +per-file KeyChainSystemService.java = file:platform/packages/apps/KeyChain:/OWNERS diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java index 86eb36c93195..23cb91db1f82 100644 --- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java +++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java @@ -49,6 +49,7 @@ import android.util.Pair; import android.util.Slog; import com.android.internal.infra.AndroidFuture; +import com.android.server.utils.Slogf; import java.util.Collections; import java.util.List; @@ -318,8 +319,8 @@ public class TrustAgentWrapper { int flags, AndroidFuture resultCallback) { if (DEBUG) { - Slog.d(TAG, "enableTrust(" + message + ", durationMs = " + durationMs - + ", flags = " + flags + ")"); + Slogf.d(TAG, "grantTrust(message=\"%s\", durationMs=%d, flags=0x%x)", + message, durationMs, flags); } Message msg = mHandler.obtainMessage( @@ -336,30 +337,32 @@ public class TrustAgentWrapper { @Override public void lockUser() { + if (DEBUG) Slog.d(TAG, "lockUser()"); mHandler.sendEmptyMessage(MSG_LOCK_USER); } @Override public void setManagingTrust(boolean managingTrust) { - if (DEBUG) Slog.d(TAG, "managingTrust()"); + if (DEBUG) Slogf.d(TAG, "setManagingTrust(%s)", managingTrust); mHandler.obtainMessage(MSG_MANAGING_TRUST, managingTrust ? 1 : 0, 0).sendToTarget(); } @Override public void onConfigureCompleted(boolean result, IBinder token) { - if (DEBUG) Slog.d(TAG, "onSetTrustAgentFeaturesEnabledCompleted(result=" + result); + if (DEBUG) Slogf.d(TAG, "onConfigureCompleted(result=%s)", result); mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_COMPLETED, result ? 1 : 0, 0, token).sendToTarget(); } @Override public void addEscrowToken(byte[] token, int userId) { + // 'token' is secret; never log it. + if (DEBUG) Slogf.d(TAG, "addEscrowToken(userId=%d)", userId); + if (mContext.getResources() .getBoolean(com.android.internal.R.bool.config_allowEscrowTokenForTrustAgent)) { - throw new SecurityException("Escrow token API is not allowed."); + throw new SecurityException("Escrow token API is not allowed."); } - - if (DEBUG) Slog.d(TAG, "adding escrow token for user " + userId); Message msg = mHandler.obtainMessage(MSG_ADD_ESCROW_TOKEN); msg.getData().putByteArray(DATA_ESCROW_TOKEN, token); msg.getData().putInt(DATA_USER_ID, userId); @@ -368,12 +371,12 @@ public class TrustAgentWrapper { @Override public void isEscrowTokenActive(long handle, int userId) { + if (DEBUG) Slogf.d(TAG, "isEscrowTokenActive(handle=%016x, userId=%d)", handle, userId); + if (mContext.getResources() .getBoolean(com.android.internal.R.bool.config_allowEscrowTokenForTrustAgent)) { throw new SecurityException("Escrow token API is not allowed."); } - - if (DEBUG) Slog.d(TAG, "checking the state of escrow token on user " + userId); Message msg = mHandler.obtainMessage(MSG_ESCROW_TOKEN_STATE); msg.getData().putLong(DATA_HANDLE, handle); msg.getData().putInt(DATA_USER_ID, userId); @@ -382,12 +385,12 @@ public class TrustAgentWrapper { @Override public void removeEscrowToken(long handle, int userId) { + if (DEBUG) Slogf.d(TAG, "removeEscrowToken(handle=%016x, userId=%d)", handle, userId); + if (mContext.getResources() .getBoolean(com.android.internal.R.bool.config_allowEscrowTokenForTrustAgent)) { throw new SecurityException("Escrow token API is not allowed."); } - - if (DEBUG) Slog.d(TAG, "removing escrow token on user " + userId); Message msg = mHandler.obtainMessage(MSG_REMOVE_ESCROW_TOKEN); msg.getData().putLong(DATA_HANDLE, handle); msg.getData().putInt(DATA_USER_ID, userId); @@ -396,12 +399,13 @@ public class TrustAgentWrapper { @Override public void unlockUserWithToken(long handle, byte[] token, int userId) { + // 'token' is secret; never log it. + if (DEBUG) Slogf.d(TAG, "unlockUserWithToken(handle=%016x, userId=%d)", handle, userId); + if (mContext.getResources() .getBoolean(com.android.internal.R.bool.config_allowEscrowTokenForTrustAgent)) { throw new SecurityException("Escrow token API is not allowed."); } - - if (DEBUG) Slog.d(TAG, "unlocking user " + userId); Message msg = mHandler.obtainMessage(MSG_UNLOCK_USER); msg.getData().putInt(DATA_USER_ID, userId); msg.getData().putLong(DATA_HANDLE, handle); @@ -411,7 +415,7 @@ public class TrustAgentWrapper { @Override public void showKeyguardErrorMessage(CharSequence message) { - if (DEBUG) Slog.d(TAG, "Showing keyguard error message: " + message); + if (DEBUG) Slogf.d(TAG, "showKeyguardErrorMessage(\"%s\")", message); Message msg = mHandler.obtainMessage(MSG_SHOW_KEYGUARD_ERROR_MESSAGE); msg.getData().putCharSequence(DATA_MESSAGE, message); msg.sendToTarget(); diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 04cd7f72acc9..e3abf0c43397 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -53,6 +53,7 @@ import android.os.Bundle; import android.os.DeadObjectException; import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; import android.os.RemoteException; @@ -150,6 +151,8 @@ public class TrustManagerService extends SystemService { private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<>(); private final Receiver mReceiver = new Receiver(); + private final Handler mHandler; + /* package */ final TrustArchive mArchive = new TrustArchive(); private final Context mContext; private final LockPatternUtils mLockPatternUtils; @@ -158,10 +161,26 @@ public class TrustManagerService extends SystemService { private VirtualDeviceManagerInternal mVirtualDeviceManager; private enum TrustState { - UNTRUSTED, // the phone is not unlocked by any trustagents - TRUSTABLE, // the phone is in a semi-locked state that can be unlocked if - // FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE is passed and a trustagent is trusted - TRUSTED // the phone is unlocked + // UNTRUSTED means that TrustManagerService is currently *not* giving permission for the + // user's Keyguard to be dismissed, and grants of trust by trust agents are remembered in + // the corresponding TrustAgentWrapper but are not recognized until the device is unlocked + // for the user. I.e., if the device is locked and the state is UNTRUSTED, it cannot be + // unlocked by a trust agent. Automotive devices are an exception; grants of trust are + // always recognized on them. + UNTRUSTED, + + // TRUSTABLE is the same as UNTRUSTED except that new grants of trust using + // FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE are recognized for moving to TRUSTED. I.e., if + // the device is locked and the state is TRUSTABLE, it can be unlocked by a trust agent, + // provided that the trust agent chooses to use Active Unlock. The TRUSTABLE state is only + // possible as a result of a downgrade from TRUSTED, after a trust agent used + // FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE in its most recent grant. + TRUSTABLE, + + // TRUSTED means that TrustManagerService is currently giving permission for the user's + // Keyguard to be dismissed. This implies that the device is unlocked for the user (where + // the case of Keyguard showing but dismissible just with swipe counts as "unlocked"). + TRUSTED }; @GuardedBy("mUserTrustState") @@ -224,13 +243,40 @@ public class TrustManagerService extends SystemService { private boolean mTrustAgentsCanRun = false; private int mCurrentUser = UserHandle.USER_SYSTEM; + /** + * A class for providing dependencies to {@link TrustManagerService} in both production and test + * cases. + */ + protected static class Injector { + private final LockPatternUtils mLockPatternUtils; + private final Looper mLooper; + + public Injector(LockPatternUtils lockPatternUtils, Looper looper) { + mLockPatternUtils = lockPatternUtils; + mLooper = looper; + } + + LockPatternUtils getLockPatternUtils() { + return mLockPatternUtils; + } + + Looper getLooper() { + return mLooper; + } + } + public TrustManagerService(Context context) { + this(context, new Injector(new LockPatternUtils(context), Looper.myLooper())); + } + + protected TrustManagerService(Context context, Injector injector) { super(context); mContext = context; + mHandler = createHandler(injector.getLooper()); mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); - mLockPatternUtils = new LockPatternUtils(context); - mStrongAuthTracker = new StrongAuthTracker(context); + mLockPatternUtils = injector.getLockPatternUtils(); + mStrongAuthTracker = new StrongAuthTracker(context, injector.getLooper()); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); mSettingsObserver = new SettingsObserver(mHandler); } @@ -814,6 +860,12 @@ public class TrustManagerService extends SystemService { } } + private TrustState getUserTrustStateInner(int userId) { + synchronized (mUserTrustState) { + return mUserTrustState.get(userId, TrustState.UNTRUSTED); + } + } + boolean isDeviceLockedInner(int userId) { synchronized (mDeviceLockedForUser) { return mDeviceLockedForUser.get(userId, true); @@ -864,7 +916,12 @@ public class TrustManagerService extends SystemService { continue; } - boolean trusted = aggregateIsTrusted(id); + final boolean trusted; + if (android.security.Flags.fixUnlockedDeviceRequiredKeys()) { + trusted = getUserTrustStateInner(id) == TrustState.TRUSTED; + } else { + trusted = aggregateIsTrusted(id); + } boolean showingKeyguard = true; boolean biometricAuthenticated = false; boolean currentUserIsUnlocked = false; @@ -1365,6 +1422,23 @@ public class TrustManagerService extends SystemService { } } + private void dispatchOnEnabledTrustAgentsChanged(int userId) { + if (DEBUG) { + Log.i(TAG, "onEnabledTrustAgentsChanged(" + userId + ")"); + } + for (int i = 0; i < mTrustListeners.size(); i++) { + try { + mTrustListeners.get(i).onEnabledTrustAgentsChanged(userId); + } catch (DeadObjectException e) { + Slog.d(TAG, "Removing dead TrustListener."); + mTrustListeners.remove(i); + i--; + } catch (RemoteException e) { + Slog.e(TAG, "Exception while notifying TrustListener.", e); + } + } + } + private void dispatchOnTrustManagedChanged(boolean managed, int userId) { if (DEBUG) { Log.i(TAG, "onTrustManagedChanged(" + managed + ", " + userId + ")"); @@ -1468,9 +1542,7 @@ public class TrustManagerService extends SystemService { @Override public void reportEnabledTrustAgentsChanged(int userId) throws RemoteException { enforceReportPermission(); - // coalesce refresh messages. - mHandler.removeMessages(MSG_ENABLED_AGENTS_CHANGED); - mHandler.sendEmptyMessage(MSG_ENABLED_AGENTS_CHANGED); + mHandler.obtainMessage(MSG_ENABLED_AGENTS_CHANGED, userId, 0).sendToTarget(); } @Override @@ -1628,7 +1700,7 @@ public class TrustManagerService extends SystemService { if (isCurrent) { fout.print(" (current)"); } - fout.print(": trusted=" + dumpBool(aggregateIsTrusted(user.id))); + fout.print(": trustState=" + getUserTrustStateInner(user.id)); fout.print(", trustManaged=" + dumpBool(aggregateIsTrustManaged(user.id))); fout.print(", deviceLocked=" + dumpBool(isDeviceLockedInner(user.id))); fout.print(", strongAuthRequired=" + dumpHex( @@ -1781,88 +1853,91 @@ public class TrustManagerService extends SystemService { } } - private final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_REGISTER_LISTENER: - addListener((ITrustListener) msg.obj); - break; - case MSG_UNREGISTER_LISTENER: - removeListener((ITrustListener) msg.obj); - break; - case MSG_DISPATCH_UNLOCK_ATTEMPT: - dispatchUnlockAttempt(msg.arg1 != 0, msg.arg2); - break; - case MSG_USER_REQUESTED_UNLOCK: - dispatchUserRequestedUnlock(msg.arg1, msg.arg2 != 0); - break; - case MSG_USER_MAY_REQUEST_UNLOCK: - dispatchUserMayRequestUnlock(msg.arg1); - break; - case MSG_DISPATCH_UNLOCK_LOCKOUT: - dispatchUnlockLockout(msg.arg1, msg.arg2); - break; - case MSG_ENABLED_AGENTS_CHANGED: - refreshAgentList(UserHandle.USER_ALL); - // This is also called when the security mode of a user changes. - refreshDeviceLockedForUser(UserHandle.USER_ALL); - break; - case MSG_KEYGUARD_SHOWING_CHANGED: - dispatchTrustableDowngrade(); - refreshDeviceLockedForUser(mCurrentUser); - break; - case MSG_START_USER: - case MSG_CLEANUP_USER: - case MSG_UNLOCK_USER: - refreshAgentList(msg.arg1); - break; - case MSG_SWITCH_USER: - mCurrentUser = msg.arg1; - mSettingsObserver.updateContentObserver(); - refreshDeviceLockedForUser(UserHandle.USER_ALL); - break; - case MSG_STOP_USER: - setDeviceLockedForUser(msg.arg1, true); - break; - case MSG_FLUSH_TRUST_USUALLY_MANAGED: - SparseBooleanArray usuallyManaged; - synchronized (mTrustUsuallyManagedForUser) { - usuallyManaged = mTrustUsuallyManagedForUser.clone(); - } + private Handler createHandler(Looper looper) { + return new Handler(looper) { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_REGISTER_LISTENER: + addListener((ITrustListener) msg.obj); + break; + case MSG_UNREGISTER_LISTENER: + removeListener((ITrustListener) msg.obj); + break; + case MSG_DISPATCH_UNLOCK_ATTEMPT: + dispatchUnlockAttempt(msg.arg1 != 0, msg.arg2); + break; + case MSG_USER_REQUESTED_UNLOCK: + dispatchUserRequestedUnlock(msg.arg1, msg.arg2 != 0); + break; + case MSG_USER_MAY_REQUEST_UNLOCK: + dispatchUserMayRequestUnlock(msg.arg1); + break; + case MSG_DISPATCH_UNLOCK_LOCKOUT: + dispatchUnlockLockout(msg.arg1, msg.arg2); + break; + case MSG_ENABLED_AGENTS_CHANGED: + refreshAgentList(UserHandle.USER_ALL); + // This is also called when the security mode of a user changes. + refreshDeviceLockedForUser(UserHandle.USER_ALL); + dispatchOnEnabledTrustAgentsChanged(msg.arg1); + break; + case MSG_KEYGUARD_SHOWING_CHANGED: + dispatchTrustableDowngrade(); + refreshDeviceLockedForUser(mCurrentUser); + break; + case MSG_START_USER: + case MSG_CLEANUP_USER: + case MSG_UNLOCK_USER: + refreshAgentList(msg.arg1); + break; + case MSG_SWITCH_USER: + mCurrentUser = msg.arg1; + mSettingsObserver.updateContentObserver(); + refreshDeviceLockedForUser(UserHandle.USER_ALL); + break; + case MSG_STOP_USER: + setDeviceLockedForUser(msg.arg1, true); + break; + case MSG_FLUSH_TRUST_USUALLY_MANAGED: + SparseBooleanArray usuallyManaged; + synchronized (mTrustUsuallyManagedForUser) { + usuallyManaged = mTrustUsuallyManagedForUser.clone(); + } - for (int i = 0; i < usuallyManaged.size(); i++) { - int userId = usuallyManaged.keyAt(i); - boolean value = usuallyManaged.valueAt(i); - if (value != mLockPatternUtils.isTrustUsuallyManaged(userId)) { - mLockPatternUtils.setTrustUsuallyManaged(value, userId); + for (int i = 0; i < usuallyManaged.size(); i++) { + int userId = usuallyManaged.keyAt(i); + boolean value = usuallyManaged.valueAt(i); + if (value != mLockPatternUtils.isTrustUsuallyManaged(userId)) { + mLockPatternUtils.setTrustUsuallyManaged(value, userId); + } } - } - break; - case MSG_REFRESH_DEVICE_LOCKED_FOR_USER: - if (msg.arg2 == 1) { - updateTrust(msg.arg1, 0 /* flags */, true /* isFromUnlock */, null); - } - final int unlockedUser = msg.getData().getInt( - REFRESH_DEVICE_LOCKED_EXCEPT_USER, UserHandle.USER_NULL); - refreshDeviceLockedForUser(msg.arg1, unlockedUser); - break; - case MSG_SCHEDULE_TRUST_TIMEOUT: - boolean shouldOverride = msg.arg1 == 1 ? true : false; - TimeoutType timeoutType = - msg.arg2 == 1 ? TimeoutType.TRUSTABLE : TimeoutType.TRUSTED; - handleScheduleTrustTimeout(shouldOverride, timeoutType); - break; - case MSG_REFRESH_TRUSTABLE_TIMERS_AFTER_AUTH: - TrustableTimeoutAlarmListener trustableAlarm = - mTrustableTimeoutAlarmListenerForUser.get(msg.arg1); - if (trustableAlarm != null && trustableAlarm.isQueued()) { - refreshTrustableTimers(msg.arg1); - } - break; + break; + case MSG_REFRESH_DEVICE_LOCKED_FOR_USER: + if (msg.arg2 == 1) { + updateTrust(msg.arg1, 0 /* flags */, true /* isFromUnlock */, null); + } + final int unlockedUser = msg.getData().getInt( + REFRESH_DEVICE_LOCKED_EXCEPT_USER, UserHandle.USER_NULL); + refreshDeviceLockedForUser(msg.arg1, unlockedUser); + break; + case MSG_SCHEDULE_TRUST_TIMEOUT: + boolean shouldOverride = msg.arg1 == 1 ? true : false; + TimeoutType timeoutType = + msg.arg2 == 1 ? TimeoutType.TRUSTABLE : TimeoutType.TRUSTED; + handleScheduleTrustTimeout(shouldOverride, timeoutType); + break; + case MSG_REFRESH_TRUSTABLE_TIMERS_AFTER_AUTH: + TrustableTimeoutAlarmListener trustableAlarm = + mTrustableTimeoutAlarmListenerForUser.get(msg.arg1); + if (trustableAlarm != null && trustableAlarm.isQueued()) { + refreshTrustableTimers(msg.arg1); + } + break; + } } - } - }; + }; + } private final PackageMonitor mPackageMonitor = new PackageMonitor() { @Override @@ -1960,8 +2035,8 @@ public class TrustManagerService extends SystemService { SparseBooleanArray mStartFromSuccessfulUnlock = new SparseBooleanArray(); - public StrongAuthTracker(Context context) { - super(context); + StrongAuthTracker(Context context, Looper looper) { + super(context, looper); } @Override diff --git a/services/tests/mockingservicestests/src/com/android/server/trust/OWNERS b/services/tests/mockingservicestests/src/com/android/server/trust/OWNERS new file mode 100644 index 000000000000..e2c6ce15b51e --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/trust/OWNERS @@ -0,0 +1 @@ +include /core/java/android/service/trust/OWNERS diff --git a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java index 33870f1d3b86..9851bc1b4be3 100644 --- a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java @@ -16,15 +16,26 @@ package com.android.server.trust; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; import static com.android.dx.mockito.inline.extended.ExtendedMockito.argThat; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anyBoolean; + +import android.Manifest; import android.annotation.Nullable; +import android.app.trust.ITrustListener; +import android.app.trust.ITrustManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -36,11 +47,16 @@ import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.net.Uri; import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; import android.os.UserHandle; import android.os.test.TestLooper; import android.provider.Settings; import android.service.trust.TrustAgentService; import android.testing.TestableContext; +import android.view.IWindowManager; +import android.view.WindowManagerGlobal; import androidx.test.core.app.ApplicationProvider; @@ -55,13 +71,16 @@ import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatcher; import org.mockito.Mock; +import org.mockito.MockitoSession; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import java.util.ArrayList; import java.util.Collections; +import java.util.Random; public class TrustManagerServiceTest { @@ -255,6 +274,43 @@ public class TrustManagerServiceTest { systemTrustAgent1); } + @Test + public void reportEnabledTrustAgentsChangedInformsListener() throws RemoteException { + final LockPatternUtils utils = mock(LockPatternUtils.class); + final TrustManagerService service = new TrustManagerService(mMockContext, + new TrustManagerService.Injector(utils, mLooper.getLooper())); + final ITrustListener trustListener = mock(ITrustListener.class); + final IWindowManager windowManager = mock(IWindowManager.class); + final int userId = new Random().nextInt(); + + mMockContext.getTestablePermissions().setPermission(Manifest.permission.TRUST_LISTENER, + PERMISSION_GRANTED); + + when(utils.getKnownTrustAgents(anyInt())).thenReturn(new ArrayList<>()); + + MockitoSession mockSession = mockitoSession() + .initMocks(this) + .mockStatic(ServiceManager.class) + .mockStatic(WindowManagerGlobal.class) + .startMocking(); + + doReturn(windowManager).when(() -> { + WindowManagerGlobal.getWindowManagerService(); + }); + + service.onStart(); + ArgumentCaptor<IBinder> binderArgumentCaptor = ArgumentCaptor.forClass(IBinder.class); + verify(() -> ServiceManager.addService(eq(Context.TRUST_SERVICE), + binderArgumentCaptor.capture(), anyBoolean(), anyInt())); + ITrustManager manager = ITrustManager.Stub.asInterface(binderArgumentCaptor.getValue()); + manager.registerTrustListener(trustListener); + mLooper.dispatchAll(); + manager.reportEnabledTrustAgentsChanged(userId); + mLooper.dispatchAll(); + verify(trustListener).onEnabledTrustAgentsChanged(eq(userId)); + mockSession.finishMocking(); + } + private void addTrustAgent(ComponentName agentComponentName, boolean isSystemApp) { ApplicationInfo applicationInfo = new ApplicationInfo(); if (isSystemApp) { diff --git a/tests/TrustTests/Android.bp b/tests/TrustTests/Android.bp index a1b888aef934..c216bced81f0 100644 --- a/tests/TrustTests/Android.bp +++ b/tests/TrustTests/Android.bp @@ -25,6 +25,7 @@ android_test { "androidx.test.rules", "androidx.test.ext.junit", "androidx.test.uiautomator_uiautomator", + "flag-junit", "mockito-target-minus-junit4", "servicestests-utils", "truth-prebuilt", diff --git a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt index f864fedf4e62..1dfd5c06167b 100644 --- a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt +++ b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt @@ -16,6 +16,10 @@ package android.trust.test +import android.content.pm.PackageManager +import android.platform.test.annotations.RequiresFlagsDisabled +import android.platform.test.annotations.RequiresFlagsEnabled +import android.platform.test.flag.junit.DeviceFlagsValueProvider import android.service.trust.GrantTrustResult import android.trust.BaseTrustAgentService import android.trust.TrustTestActivity @@ -27,6 +31,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import androidx.test.uiautomator.UiDevice import com.android.server.testutils.mock +import org.junit.Assume.assumeFalse import org.junit.Before import org.junit.Rule import org.junit.Test @@ -45,6 +50,7 @@ class GrantAndRevokeTrustTest { private val activityScenarioRule = ActivityScenarioRule(TrustTestActivity::class.java) private val lockStateTrackingRule = LockStateTrackingRule() private val trustAgentRule = TrustAgentRule<GrantAndRevokeTrustAgent>() + private val packageManager = getInstrumentation().getTargetContext().getPackageManager() @get:Rule val rule: RuleChain = RuleChain @@ -52,6 +58,7 @@ class GrantAndRevokeTrustTest { .around(ScreenLockRule()) .around(lockStateTrackingRule) .around(trustAgentRule) + .around(DeviceFlagsValueProvider.createCheckFlagsRule()) @Before fun manageTrust() { @@ -72,7 +79,7 @@ class GrantAndRevokeTrustTest { trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0) {} uiDevice.sleep() - lockStateTrackingRule.assertUnlocked() + lockStateTrackingRule.assertUnlockedAndTrusted() } @Test @@ -86,6 +93,51 @@ class GrantAndRevokeTrustTest { } @Test + @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) + fun grantCannotActivelyUnlockDevice() { + // On automotive, trust agents can actively unlock the device. + assumeFalse(packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) + + // Lock the device. + uiDevice.sleep() + lockStateTrackingRule.assertLocked() + + // Grant trust. + trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0) {} + + // The grant should not have unlocked the device. Wait a bit so that + // TrustManagerService probably will have finished processing the grant. + await() + lockStateTrackingRule.assertLocked() + + // Turn the screen on and off to cause TrustManagerService to refresh + // its deviceLocked state. Then verify the state is still locked. This + // part failed before the fix for b/296464083. + uiDevice.wakeUp() + uiDevice.sleep() + await() + lockStateTrackingRule.assertLocked() + } + + @Test + @RequiresFlagsDisabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) + fun grantCouldCauseWrongDeviceLockedStateDueToBug() { + // On automotive, trust agents can actively unlock the device. + assumeFalse(packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) + + // Verify that b/296464083 exists. That is, when the device is locked + // and a trust agent grants trust, the deviceLocked state incorrectly + // becomes false even though the device correctly remains locked. + uiDevice.sleep() + lockStateTrackingRule.assertLocked() + trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0) {} + uiDevice.wakeUp() + uiDevice.sleep() + await() + lockStateTrackingRule.assertUnlockedButNotReally() + } + + @Test fun grantDoesNotCallBack() { val callback = mock<(GrantTrustResult) -> Unit>() trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, 0, callback) diff --git a/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt b/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt index ae722477a2bc..96362b8e71dc 100644 --- a/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt +++ b/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt @@ -102,7 +102,7 @@ class TemporaryAndRenewableTrustTest { trustAgentRule.agent.grantTrust( GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {} - lockStateTrackingRule.assertUnlocked() + lockStateTrackingRule.assertUnlockedAndTrusted() } @Test @@ -125,7 +125,7 @@ class TemporaryAndRenewableTrustTest { Log.i(TAG, "Callback received; status=${it.status}") result = it } - lockStateTrackingRule.assertUnlocked() + lockStateTrackingRule.assertUnlockedAndTrusted() wait("callback triggered") { result?.status == STATUS_UNLOCKED_BY_GRANT } } diff --git a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt index 1930a1c8bbb2..fe47fde9b268 100644 --- a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt +++ b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt @@ -16,6 +16,7 @@ package android.trust.test.lib +import android.app.KeyguardManager import android.app.trust.TrustManager import android.app.trust.TrustManager.TrustListener import android.content.Context @@ -27,18 +28,23 @@ import org.junit.runner.Description import org.junit.runners.model.Statement /** - * Rule for tracking the lock state of the device based on events emitted to [TrustListener]. + * Rule for tracking the trusted state of the device based on events emitted to + * [TrustListener]. Provides helper methods for verifying that the trusted + * state has a particular value and is consistent with (a) the keyguard "locked" + * (i.e. showing) value when applicable, and (b) the device locked value that is + * tracked by TrustManagerService and is queryable via KeyguardManager. */ class LockStateTrackingRule : TestRule { private val context: Context = getApplicationContext() - private val windowManager = WindowManagerGlobal.getWindowManagerService() + private val windowManager = checkNotNull(WindowManagerGlobal.getWindowManagerService()) + private val keyguardManager = context.getSystemService(KeyguardManager::class.java) as KeyguardManager - @Volatile lateinit var lockState: LockState + @Volatile lateinit var trustState: TrustState private set override fun apply(base: Statement, description: Description) = object : Statement() { override fun evaluate() { - lockState = LockState(locked = windowManager.isKeyguardLocked) + trustState = TrustState() val trustManager = context.getSystemService(TrustManager::class.java) as TrustManager val listener = Listener() @@ -52,12 +58,25 @@ class LockStateTrackingRule : TestRule { } fun assertLocked() { - wait("un-locked per TrustListener") { lockState.locked == true } - wait("keyguard lock") { windowManager.isKeyguardLocked } + wait("device locked") { keyguardManager.isDeviceLocked } + // isDeviceLocked implies isKeyguardLocked && !trusted. + wait("keyguard locked") { windowManager.isKeyguardLocked } + wait("not trusted") { trustState.trusted == false } } - fun assertUnlocked() { - wait("locked per TrustListener") { lockState.locked == false } + // TODO(b/299298338) remove this when removing FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS + fun assertUnlockedButNotReally() { + wait("device unlocked") { !keyguardManager.isDeviceLocked } + wait("not trusted") { trustState.trusted == false } + wait("keyguard locked") { windowManager.isKeyguardLocked } + } + + fun assertUnlockedAndTrusted() { + wait("device unlocked") { !keyguardManager.isDeviceLocked } + wait("trusted") { trustState.trusted == true } + // Can't check for !isKeyguardLocked here, since isKeyguardLocked + // returns true in the case where the keyguard is dismissible with + // swipe, which is considered "device unlocked"! } inner class Listener : TrustListener { @@ -69,7 +88,7 @@ class LockStateTrackingRule : TestRule { trustGrantedMessages: MutableList<String> ) { Log.d(TAG, "Device became trusted=$enabled") - lockState = lockState.copy(locked = !enabled) + trustState = trustState.copy(trusted=enabled) } override fun onTrustManagedChanged(enabled: Boolean, userId: Int) { @@ -77,10 +96,13 @@ class LockStateTrackingRule : TestRule { override fun onTrustError(message: CharSequence) { } + + override fun onEnabledTrustAgentsChanged(userId: Int) { + } } - data class LockState( - val locked: Boolean? = null + data class TrustState( + val trusted: Boolean? = null ) companion object { diff --git a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt index 4189baae10cb..f1edca3ff86e 100644 --- a/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt +++ b/tests/TrustTests/src/android/trust/test/lib/ScreenLockRule.kt @@ -36,7 +36,7 @@ import org.junit.runners.model.Statement class ScreenLockRule : TestRule { private val context: Context = getApplicationContext() private val uiDevice = UiDevice.getInstance(getInstrumentation()) - private val windowManager = WindowManagerGlobal.getWindowManagerService() + private val windowManager = checkNotNull(WindowManagerGlobal.getWindowManagerService()) private val lockPatternUtils = LockPatternUtils(context) private var instantLockSavedValue = false diff --git a/tools/aapt/ZipEntry.cpp b/tools/aapt/ZipEntry.cpp index 5339285f5667..6886993fbfa1 100644 --- a/tools/aapt/ZipEntry.cpp +++ b/tools/aapt/ZipEntry.cpp @@ -18,6 +18,8 @@ // Access to entries in a Zip archive. // +#define _POSIX_THREAD_SAFE_FUNCTIONS // For mingw localtime_r(). + #define LOG_TAG "zip" #include "ZipEntry.h" @@ -337,39 +339,26 @@ time_t ZipEntry::getModWhen(void) const /* * Set the CDE/LFH timestamp from UNIX time. */ -void ZipEntry::setModWhen(time_t when) -{ -#if !defined(_WIN32) - struct tm tmResult; -#endif - time_t even; - unsigned short zdate, ztime; - - struct tm* ptm; - +void ZipEntry::setModWhen(time_t when) { /* round up to an even number of seconds */ - even = (time_t)(((unsigned long)(when) + 1) & (~1)); + time_t even = (time_t)(((unsigned long)(when) + 1) & (~1)); /* expand */ -#if !defined(_WIN32) - ptm = localtime_r(&even, &tmResult); -#else - ptm = localtime(&even); -#endif + struct tm tmResult; + struct tm* ptm = localtime_r(&even, &tmResult); int year; year = ptm->tm_year; if (year < 80) year = 80; - zdate = (year - 80) << 9 | (ptm->tm_mon+1) << 5 | ptm->tm_mday; - ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1; + unsigned short zdate = (year - 80) << 9 | (ptm->tm_mon + 1) << 5 | ptm->tm_mday; + unsigned short ztime = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1; mCDE.mLastModFileTime = mLFH.mLastModFileTime = ztime; mCDE.mLastModFileDate = mLFH.mLastModFileDate = zdate; } - /* * =========================================================================== * ZipEntry::LocalFileHeader diff --git a/tools/aapt2/compile/InlineXmlFormatParser.h b/tools/aapt2/compile/InlineXmlFormatParser.h index 4300023e7726..3a5161b828da 100644 --- a/tools/aapt2/compile/InlineXmlFormatParser.h +++ b/tools/aapt2/compile/InlineXmlFormatParser.h @@ -21,8 +21,8 @@ #include <vector> #include "android-base/macros.h" - #include "process/IResourceTableConsumer.h" +#include "xml/XmlDom.h" namespace aapt { diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp index 9828b97982ed..f93949bab341 100644 --- a/tools/aapt2/dump/DumpManifest.cpp +++ b/tools/aapt2/dump/DumpManifest.cpp @@ -116,9 +116,7 @@ class CommonFeatureGroup; class ManifestExtractor { public: - - explicit ManifestExtractor(LoadedApk* apk, DumpManifestOptions& options) - : apk_(apk), options_(options) { } + explicit ManifestExtractor(LoadedApk* apk, DumpManifestOptions& options); class Element { public: @@ -387,7 +385,7 @@ class ManifestExtractor { DumpManifestOptions& options_; private: - std::unique_ptr<CommonFeatureGroup> commonFeatureGroup_ = util::make_unique<CommonFeatureGroup>(); + std::unique_ptr<CommonFeatureGroup> commonFeatureGroup_; std::map<std::string, ConfigDescription> locales_; std::map<uint16_t, ConfigDescription> densities_; std::vector<Element*> parent_stack_; @@ -1970,6 +1968,12 @@ static void Print(ManifestExtractor::Element* el, text::Printer* printer) { } } +// Define this constructor after the CommonFeatureGroup class definition to avoid errors with using +// std::unique_ptr on an incomplete type. +ManifestExtractor::ManifestExtractor(LoadedApk* apk, DumpManifestOptions& options) + : apk_(apk), options_(options), commonFeatureGroup_(util::make_unique<CommonFeatureGroup>()) { +} + bool ManifestExtractor::Dump(text::Printer* printer, IDiagnostics* diag) { // Load the manifest std::unique_ptr<xml::XmlResource> doc = apk_->LoadXml("AndroidManifest.xml", diag); diff --git a/tools/lint/common/Android.bp b/tools/lint/common/Android.bp index 898f88b8759c..8bfbfe5f60b3 100644 --- a/tools/lint/common/Android.bp +++ b/tools/lint/common/Android.bp @@ -27,3 +27,30 @@ java_library_host { libs: ["lint_api"], kotlincflags: ["-Xjvm-default=all"], } + +java_defaults { + name: "AndroidLintCheckerTestDefaults", + srcs: ["checks/src/test/java/**/*.kt"], + static_libs: [ + "junit", + "lint", + "lint_tests", + ], + test_options: { + unit_test: true, + tradefed_options: [ + { + // lint bundles in some classes that were built with older versions + // of libraries, and no longer load. Since tradefed tries to load + // all classes in the jar to look for tests, it crashes loading them. + // Exclude these classes from tradefed's search. + name: "exclude-paths", + value: "org/apache", + }, + { + name: "exclude-paths", + value: "META-INF", + }, + ], + }, +} diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/AidlImplementationDetector.kt b/tools/lint/common/src/main/java/com/google/android/lint/aidl/AidlImplementationDetector.kt index ab6d871d6ea6..ab6d871d6ea6 100644 --- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/AidlImplementationDetector.kt +++ b/tools/lint/common/src/main/java/com/google/android/lint/aidl/AidlImplementationDetector.kt diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt b/tools/lint/common/src/main/java/com/google/android/lint/aidl/Constants.kt index e03d92ab44a0..e03d92ab44a0 100644 --- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt +++ b/tools/lint/common/src/main/java/com/google/android/lint/aidl/Constants.kt diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt b/tools/lint/common/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt index d41fee3fc0dc..d41fee3fc0dc 100644 --- a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt +++ b/tools/lint/common/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt diff --git a/tools/lint/fix/soong_lint_fix.py b/tools/lint/fix/soong_lint_fix.py index cd4d778d1dec..acc0ad043171 100644 --- a/tools/lint/fix/soong_lint_fix.py +++ b/tools/lint/fix/soong_lint_fix.py @@ -29,6 +29,39 @@ PATH_PREFIX = "out/soong/.intermediates" PATH_SUFFIX = "android_common/lint" FIX_ZIP = "suggested-fixes.zip" + +class SoongModule: + """A Soong module to lint. + + The constructor takes the name of the module (for example, + "framework-minus-apex"). find() must be called to extract the intermediate + module path from Soong's module-info.json + """ + def __init__(self, name): + self._name = name + + def find(self, module_info): + """Finds the module in the loaded module_info.json.""" + if self._name not in module_info: + raise Exception(f"Module {self._name} not found!") + + partial_path = module_info[self._name]["path"][0] + print(f"Found module {partial_path}/{self._name}.") + self._path = f"{PATH_PREFIX}/{partial_path}/{self._name}/{PATH_SUFFIX}" + + @property + def name(self): + return self._name + + @property + def lint_report(self): + return f"{self._path}/lint-report.txt" + + @property + def suggested_fixes(self): + return f"{self._path}/{FIX_ZIP}" + + class SoongLintFix: """ This class creates a command line tool that will @@ -53,16 +86,14 @@ class SoongLintFix: self._parser = _setup_parser() self._args = None self._kwargs = None - self._path = None - self._target = None - + self._modules = [] - def run(self, additional_setup=None, custom_fix=None): + def run(self): """ Run the script """ self._setup() - self._find_module() + self._find_modules() self._lint() if not self._args.no_fix: @@ -87,8 +118,6 @@ class SoongLintFix: os.chdir(ANDROID_BUILD_TOP) - - def _find_module(self): print("Refreshing soong modules...") try: os.mkdir(ANDROID_PRODUCT_OUT) @@ -97,48 +126,47 @@ class SoongLintFix: subprocess.call(f"{SOONG_UI} --make-mode {PRODUCT_OUT}/module-info.json", **self._kwargs) print("done.") + + def _find_modules(self): with open(f"{ANDROID_PRODUCT_OUT}/module-info.json") as f: module_info = json.load(f) - if self._args.module not in module_info: - sys.exit(f"Module {self._args.module} not found!") - - module_path = module_info[self._args.module]["path"][0] - print(f"Found module {module_path}/{self._args.module}.") - - self._path = f"{PATH_PREFIX}/{module_path}/{self._args.module}/{PATH_SUFFIX}" - self._target = f"{self._path}/lint-report.txt" - + for module_name in self._args.modules: + module = SoongModule(module_name) + module.find(module_info) + self._modules.append(module) def _lint(self): print("Cleaning up any old lint results...") - try: - os.remove(f"{self._target}") - os.remove(f"{self._path}/{FIX_ZIP}") - except FileNotFoundError: - pass + for module in self._modules: + try: + os.remove(f"{module.lint_report}") + os.remove(f"{module.suggested_fixes}") + except FileNotFoundError: + pass print("done.") - print(f"Generating {self._target}") - subprocess.call(f"{SOONG_UI} --make-mode {self._target}", **self._kwargs) + target = " ".join([ module.lint_report for module in self._modules ]) + print(f"Generating {target}") + subprocess.call(f"{SOONG_UI} --make-mode {target}", **self._kwargs) print("done.") - def _fix(self): - print("Copying suggested fixes to the tree...") - with zipfile.ZipFile(f"{self._path}/{FIX_ZIP}") as zip: - for name in zip.namelist(): - if name.startswith("out") or not name.endswith(".java"): - continue - with zip.open(name) as src, open(f"{ANDROID_BUILD_TOP}/{name}", "wb") as dst: - shutil.copyfileobj(src, dst) + for module in self._modules: + print(f"Copying suggested fixes for {module.name} to the tree...") + with zipfile.ZipFile(f"{module.suggested_fixes}") as zip: + for name in zip.namelist(): + if name.startswith("out") or not name.endswith(".java"): + continue + with zip.open(name) as src, open(f"{ANDROID_BUILD_TOP}/{name}", "wb") as dst: + shutil.copyfileobj(src, dst) print("done.") - def _print(self): - print("### lint-report.txt ###", end="\n\n") - with open(self._target, "r") as f: - print(f.read()) + for module in self._modules: + print(f"### lint-report.txt {module.name} ###", end="\n\n") + with open(module.lint_report, "r") as f: + print(f.read()) def _setup_parser(): @@ -151,7 +179,8 @@ def _setup_parser(): **Gotcha**: You must have run `source build/envsetup.sh` and `lunch` first. """, formatter_class=argparse.RawTextHelpFormatter) - parser.add_argument('module', + parser.add_argument('modules', + nargs='+', help='The soong build module to run ' '(e.g. framework-minus-apex or services.core.unboosted)') @@ -170,4 +199,4 @@ def _setup_parser(): return parser if __name__ == "__main__": - SoongLintFix().run()
\ No newline at end of file + SoongLintFix().run() diff --git a/tools/lint/framework/Android.bp b/tools/lint/framework/Android.bp index 30a6daaef2a4..5acdf436ae08 100644 --- a/tools/lint/framework/Android.bp +++ b/tools/lint/framework/Android.bp @@ -37,28 +37,9 @@ java_library_host { java_test_host { name: "AndroidFrameworkLintCheckerTest", + defaults: ["AndroidLintCheckerTestDefaults"], srcs: ["checks/src/test/java/**/*.kt"], static_libs: [ "AndroidFrameworkLintChecker", - "junit", - "lint", - "lint_tests", ], - test_options: { - unit_test: true, - tradefed_options: [ - { - // lint bundles in some classes that were built with older versions - // of libraries, and no longer load. Since tradefed tries to load - // all classes in the jar to look for tests, it crashes loading them. - // Exclude these classes from tradefed's search. - name: "exclude-paths", - value: "org/apache", - }, - { - name: "exclude-paths", - value: "META-INF", - }, - ], - }, } diff --git a/tools/lint/global/Android.bp b/tools/lint/global/Android.bp index bedb7bd78a29..3e74171814ab 100644 --- a/tools/lint/global/Android.bp +++ b/tools/lint/global/Android.bp @@ -38,28 +38,9 @@ java_library_host { java_test_host { name: "AndroidGlobalLintCheckerTest", + defaults: ["AndroidLintCheckerTestDefaults"], srcs: ["checks/src/test/java/**/*.kt"], static_libs: [ "AndroidGlobalLintChecker", - "junit", - "lint", - "lint_tests", ], - test_options: { - unit_test: true, - tradefed_options: [ - { - // lint bundles in some classes that were built with older versions - // of libraries, and no longer load. Since tradefed tries to load - // all classes in the jar to look for tests, it crashes loading them. - // Exclude these classes from tradefed's search. - name: "exclude-paths", - value: "org/apache", - }, - { - name: "exclude-paths", - value: "META-INF", - }, - ], - }, } diff --git a/tools/lint/utils/Android.bp b/tools/lint/utils/Android.bp new file mode 100644 index 000000000000..75e8d6863c20 --- /dev/null +++ b/tools/lint/utils/Android.bp @@ -0,0 +1,45 @@ +// Copyright (C) 2023 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 { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +java_library_host { + name: "AndroidUtilsLintChecker", + srcs: ["checks/src/main/java/**/*.kt"], + plugins: ["auto_service_plugin"], + libs: [ + "auto_service_annotations", + "lint_api", + ], + static_libs: [ + "AndroidCommonLint", + ], + kotlincflags: ["-Xjvm-default=all"], +} + +java_test_host { + name: "AndroidUtilsLintCheckerTest", + defaults: ["AndroidLintCheckerTestDefaults"], + srcs: ["checks/src/test/java/**/*.kt"], + static_libs: [ + "AndroidUtilsLintChecker", + ], +} diff --git a/tools/lint/utils/checks/src/main/java/com/google/android/lint/AndroidUtilsIssueRegistry.kt b/tools/lint/utils/checks/src/main/java/com/google/android/lint/AndroidUtilsIssueRegistry.kt new file mode 100644 index 000000000000..fa61c42ef8e6 --- /dev/null +++ b/tools/lint/utils/checks/src/main/java/com/google/android/lint/AndroidUtilsIssueRegistry.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2023 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.google.android.lint + +import com.android.tools.lint.client.api.IssueRegistry +import com.android.tools.lint.client.api.Vendor +import com.android.tools.lint.detector.api.CURRENT_API +import com.google.android.lint.aidl.AnnotatedAidlCounter +import com.google.auto.service.AutoService + +@AutoService(IssueRegistry::class) +@Suppress("UnstableApiUsage") +class AndroidUtilsIssueRegistry : IssueRegistry() { + override val issues = listOf( + AnnotatedAidlCounter.ISSUE_ANNOTATED_AIDL_COUNTER, + ) + + override val api: Int + get() = CURRENT_API + + override val minApi: Int + get() = 8 + + override val vendor: Vendor = Vendor( + vendorName = "Android", + feedbackUrl = "http://b/issues/new?component=315013", + contact = "tweek@google.com" + ) +} diff --git a/tools/lint/utils/checks/src/main/java/com/google/android/lint/aidl/AnnotatedAidlCounter.kt b/tools/lint/utils/checks/src/main/java/com/google/android/lint/aidl/AnnotatedAidlCounter.kt new file mode 100644 index 000000000000..f0ec3f44f6c4 --- /dev/null +++ b/tools/lint/utils/checks/src/main/java/com/google/android/lint/aidl/AnnotatedAidlCounter.kt @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2023 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.google.android.lint.aidl + +import com.android.tools.lint.detector.api.Category +import com.android.tools.lint.detector.api.Context +import com.android.tools.lint.detector.api.Implementation +import com.android.tools.lint.detector.api.Issue +import com.android.tools.lint.detector.api.JavaContext +import com.android.tools.lint.detector.api.Location +import com.android.tools.lint.detector.api.Scope +import com.android.tools.lint.detector.api.Severity +import org.jetbrains.uast.UBlockExpression +import org.jetbrains.uast.UMethod + +import java.util.TreeMap + +/** + * Count the number of AIDL interfaces. Reports the number of annotated and + * non-annotated methods. + */ +@Suppress("UnstableApiUsage") +class AnnotatedAidlCounter : AidlImplementationDetector() { + + private data class Stat( + var unannotated: Int = 0, + var enforced: Int = 0, + var notRequired: Int = 0, + ) + + private var packagesStats: TreeMap<String, Stat> = TreeMap<String, Stat>() + + override fun visitAidlMethod( + context: JavaContext, + node: UMethod, + interfaceName: String, + body: UBlockExpression + ) { + val packageName = context.uastFile?.packageName ?: "<unknown>" + var packageStat = packagesStats.getOrDefault(packageName, Stat()) + when { + node.hasAnnotation(ANNOTATION_ENFORCE_PERMISSION) -> packageStat.enforced += 1 + node.hasAnnotation(ANNOTATION_REQUIRES_NO_PERMISSION) -> packageStat.notRequired += 1 + else -> packageStat.unannotated += 1 + } + packagesStats.put(packageName, packageStat) + // context.driver.client.log(null, "%s.%s#%s".format(packageName, interfaceName, node.name)) + } + + override fun afterCheckRootProject(context: Context) { + var total = Stat() + for ((packageName, stat) in packagesStats) { + context.client.log(null, "package $packageName => $stat") + total.unannotated += stat.unannotated + total.enforced += stat.enforced + total.notRequired += stat.notRequired + } + val location = Location.create(context.project.dir) + context.report( + ISSUE_ANNOTATED_AIDL_COUNTER, + location, + "module ${context.project.name} => $total" + ) + } + + companion object { + + @JvmField + val ISSUE_ANNOTATED_AIDL_COUNTER = Issue.create( + id = "AnnotatedAidlCounter", + briefDescription = "Statistics on the number of annotated AIDL methods.", + explanation = "", + category = Category.SECURITY, + priority = 5, + severity = Severity.INFORMATIONAL, + implementation = Implementation( + AnnotatedAidlCounter::class.java, + Scope.JAVA_FILE_SCOPE + ), + ) + } +} diff --git a/tools/lint/utils/checks/src/test/java/com/google/android/lint/aidl/AnnotatedAidlCounterTest.kt b/tools/lint/utils/checks/src/test/java/com/google/android/lint/aidl/AnnotatedAidlCounterTest.kt new file mode 100644 index 000000000000..692b7da243c9 --- /dev/null +++ b/tools/lint/utils/checks/src/test/java/com/google/android/lint/aidl/AnnotatedAidlCounterTest.kt @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2023 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.google.android.lint.aidl + +import com.android.tools.lint.checks.infrastructure.LintDetectorTest +import com.android.tools.lint.checks.infrastructure.TestFile +import com.android.tools.lint.checks.infrastructure.TestLintTask +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Issue + +@Suppress("UnstableApiUsage") +class AnnotatedAidlCounterTest : LintDetectorTest() { + override fun getDetector(): Detector = AnnotatedAidlCounter() + + override fun getIssues(): List<Issue> = listOf( + AnnotatedAidlCounter.ISSUE_ANNOTATED_AIDL_COUNTER, + ) + + override fun lint(): TestLintTask = super.lint().allowMissingSdk(true) + + /** No issue scenario */ + + fun testDoesNotDetectIssuesCorrectAnnotationOnMethod() { + lint().files(java( + """ + package test.pkg; + import android.annotation.EnforcePermission; + public class TestClass2 extends IFooMethod.Stub { + @Override + @EnforcePermission(android.Manifest.permission.READ_PHONE_STATE) + public void testMethod() {} + } + """).indented(), + *stubs + ) + .run() + .expect(""" + app: Information: module app => Stat(unannotated=0, enforced=1, notRequired=0) [AnnotatedAidlCounter] + 0 errors, 0 warnings + """) + } + + // A service with permission annotation on the method. + private val interfaceIFooMethodStub: TestFile = java( + """ + public interface IFooMethod extends android.os.IInterface { + public static abstract class Stub extends android.os.Binder implements IFooMethod {} + @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE) + public void testMethod(); + } + """ + ).indented() + + // A service without any permission annotation. + private val interfaceIBarStub: TestFile = java( + """ + public interface IBar extends android.os.IInterface { + public static abstract class Stub extends android.os.Binder implements IBar { + @Override + public void testMethod() {} + } + public void testMethod(); + } + """ + ).indented() + + private val manifestPermissionStub: TestFile = java( + """ + package android.Manifest; + class permission { + public static final String READ_PHONE_STATE = "android.permission.READ_PHONE_STATE"; + } + """ + ).indented() + + private val enforcePermissionAnnotationStub: TestFile = java( + """ + package android.annotation; + public @interface EnforcePermission {} + """ + ).indented() + + private val stubs = arrayOf(interfaceIFooMethodStub, interfaceIBarStub, + manifestPermissionStub, enforcePermissionAnnotationStub) +} |