Merge "Don't depend on String8 cast to C string" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 9f48bf4..55f5436 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -18,8 +18,11 @@
// 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 @@
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 @@
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"],
+}
diff --git a/OWNERS b/OWNERS
index 6c25324..4e5c7d8 100644
--- a/OWNERS
+++ b/OWNERS
@@ -28,7 +28,7 @@
# 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 8129d99..b1edc18 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 5d7d7ba..da6a6d4 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -9,6 +9,11 @@
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 e4ac0119..8d44784 100644
--- a/core/java/android/app/trust/ITrustListener.aidl
+++ b/core/java/android/app/trust/ITrustListener.aidl
@@ -24,6 +24,7 @@
* {@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 62f755d..3552ce0 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -43,6 +43,7 @@
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 @@
}
@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 @@
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 @@
* @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 0000000..ebfe66f5
--- /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 0000000..851aa6d
--- /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 0000000..b6c2b83
--- /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 6182253..11e43dd 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2434,6 +2434,7 @@
* @see #getId()
*/
@IdRes
+ @ViewDebug.ExportedProperty(resolveId = true)
int mID = NO_ID;
/** The ID of this view for autofill purposes.
@@ -4240,6 +4241,71 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* accessing these directly.
* {@hide}
*/
+ @ViewDebug.ExportedProperty(category = "scrolling")
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
protected int mScrollX;
/**
@@ -4398,6 +4469,7 @@
* accessing these directly.
* {@hide}
*/
+ @ViewDebug.ExportedProperty(category = "scrolling")
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
protected int mScrollY;
@@ -4406,6 +4478,7 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* @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 @@
* @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 @@
* @return The top of this view, in pixels.
*/
@ViewDebug.CapturedViewProperty
- @ViewDebug.ExportedProperty(category = "layout")
public final int getTop() {
return mTop;
}
@@ -17985,7 +18058,6 @@
* @return The bottom of this view, in pixels.
*/
@ViewDebug.CapturedViewProperty
- @ViewDebug.ExportedProperty(category = "layout")
public final int getBottom() {
return mBottom;
}
@@ -18051,7 +18123,6 @@
* @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 @@
* @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 @@
* @return the top padding in pixels
*/
@InspectableProperty
- @ViewDebug.ExportedProperty(category = "padding")
public int getPaddingTop() {
return mPaddingTop;
}
@@ -25333,7 +25402,6 @@
* @return the bottom padding in pixels
*/
@InspectableProperty
- @ViewDebug.ExportedProperty(category = "padding")
public int getPaddingBottom() {
return mPaddingBottom;
}
@@ -25346,7 +25414,6 @@
* @return the left padding in pixels
*/
@InspectableProperty
- @ViewDebug.ExportedProperty(category = "padding")
public int getPaddingLeft() {
if (!isPaddingResolved()) {
resolvePadding();
@@ -25377,7 +25444,6 @@
* @return the right padding in pixels
*/
@InspectableProperty
- @ViewDebug.ExportedProperty(category = "padding")
public int getPaddingRight() {
if (!isPaddingResolved()) {
resolvePadding();
@@ -26063,7 +26129,6 @@
*/
@IdRes
@ViewDebug.CapturedViewProperty
- @ViewDebug.ExportedProperty(resolveId = true)
@InspectableProperty
public int getId() {
return mID;
@@ -27026,71 +27091,6 @@
* @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 5bc48c5..c9d9926 100644
--- a/core/java/com/android/internal/util/FileRotator.java
+++ b/core/java/com/android/internal/util/FileRotator.java
@@ -19,6 +19,9 @@
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.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 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 bbaea0a..418000f 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1806,15 +1806,10 @@
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 0000000..5aeab42
--- /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 95272132..73e47e1 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 @@
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 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 375d785..0000000
--- 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 f3e1524..0000000
--- 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 2fd99ab..0000000
--- 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 369205e..0000000
--- 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 b981d83..0000000
--- 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 dc2185ea..daed277 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -99,6 +99,13 @@
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() = 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 0000000..b679328
--- /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 0000000..b679328
--- /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 0000000..b679328
--- /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 0cd8b45..5b2409a 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -6,6 +6,7 @@
aaliomer@google.com
aaronjli@google.com
+achalke@google.com
acul@google.com
adamcohen@google.com
aioana@google.com
@@ -72,6 +73,7 @@
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 @@
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 a08f540..6507488 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -549,6 +549,18 @@
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 feff216..7394005 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -322,4 +322,9 @@
* 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 d90f328..e912053 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 @@
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 f1269f2..f4cf4ef 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 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 b1051af..417eb40 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.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 @@
}
@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 8f363ef..d787ada 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 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 @@
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 930f49e..ff5f509f 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 @@
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 846c2d9..a53d096 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 @@
}
@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 bfccd58..53fbe8f 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 @@
.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 f408d7c..fa4bf22 100644
--- a/services/core/java/com/android/server/security/OWNERS
+++ b/services/core/java/com/android/server/security/OWNERS
@@ -4,3 +4,4 @@
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 86eb36c93..23cb91d 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.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 @@
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 @@
@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 @@
@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 @@
@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 @@
@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 @@
@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 04cd7f7..e3abf0c 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.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 @@
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 @@
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 @@
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 @@
}
}
+ 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 @@
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 @@
}
}
+ 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 @@
@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 @@
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 @@
}
}
- 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();
- }
-
- 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);
+ 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();
}
- }
- 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;
+
+ 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;
+ }
}
- }
- };
+ };
+ }
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override
@@ -1960,8 +2035,8 @@
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 0000000..e2c6ce1
--- /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 33870f1..9851bc1 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.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.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 @@
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 a1b888a..c216bce 100644
--- a/tests/TrustTests/Android.bp
+++ b/tests/TrustTests/Android.bp
@@ -25,6 +25,7 @@
"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 f864fed..1dfd5c0 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.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 @@
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 @@
.around(ScreenLockRule())
.around(lockStateTrackingRule)
.around(trustAgentRule)
+ .around(DeviceFlagsValueProvider.createCheckFlagsRule())
@Before
fun manageTrust() {
@@ -72,7 +79,7 @@
trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0) {}
uiDevice.sleep()
- lockStateTrackingRule.assertUnlocked()
+ lockStateTrackingRule.assertUnlockedAndTrusted()
}
@Test
@@ -86,6 +93,51 @@
}
@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 ae72247..96362b8 100644
--- a/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt
+++ b/tests/TrustTests/src/android/trust/test/TemporaryAndRenewableTrustTest.kt
@@ -102,7 +102,7 @@
trustAgentRule.agent.grantTrust(
GRANT_MESSAGE, 0, FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) {}
- lockStateTrackingRule.assertUnlocked()
+ lockStateTrackingRule.assertUnlockedAndTrusted()
}
@Test
@@ -125,7 +125,7 @@
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 1930a1c..fe47fde 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.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 @@
}
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 @@
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 @@
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 4189baa..f1edca3 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 @@
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 5339285..6886993 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 @@
/*
* 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 4300023..3a5161b 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 9828b97..f93949b 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -116,9 +116,7 @@
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 @@
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 @@
}
}
+// 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 898f88b..8bfbfe5 100644
--- a/tools/lint/common/Android.bp
+++ b/tools/lint/common/Android.bp
@@ -27,3 +27,30 @@
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
similarity index 100%
rename from tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/AidlImplementationDetector.kt
rename to 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
similarity index 100%
rename from tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt
rename to 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
similarity index 100%
rename from tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
rename to 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 cd4d778d..acc0ad0 100644
--- a/tools/lint/fix/soong_lint_fix.py
+++ b/tools/lint/fix/soong_lint_fix.py
@@ -29,6 +29,39 @@
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 @@
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 @@
os.chdir(ANDROID_BUILD_TOP)
-
- def _find_module(self):
print("Refreshing soong modules...")
try:
os.mkdir(ANDROID_PRODUCT_OUT)
@@ -97,48 +126,47 @@
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 @@
**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 @@
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 30a6daa..5acdf43 100644
--- a/tools/lint/framework/Android.bp
+++ b/tools/lint/framework/Android.bp
@@ -37,28 +37,9 @@
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 bedb7bd..3e74171 100644
--- a/tools/lint/global/Android.bp
+++ b/tools/lint/global/Android.bp
@@ -38,28 +38,9 @@
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 0000000..75e8d68
--- /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 0000000..fa61c42
--- /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 0000000..f0ec3f4
--- /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 0000000..692b7da
--- /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)
+}