Commit 447a31e9 authored by Fabian Henneke's avatar Fabian Henneke Committed by Chromium LUCI CQ

Expose passwords to compatibility Autofill

Android's Autofill framework interacts with Chrome via an Accessibility-
based compatibility bridge. In order to allow it to see (and thus offer
to save) unmasked passwords, these need to be exposed to Accessibility
services. However, since Android O the policy for password fields is to
preserve their current masking state in all matters related to
Accessibility.

With this change, passwords will be exposed to Accessibility unmasked if
the only consumer of Accessibility information is the Autofill
framework's CompatibilityBridge. As the bridge hooks directly into the
AccessibilityManager via an AccessibilityPolicy, this situation can be
detected easily by checking that the ENABLED_ACCESSIBILITY_SERVICES
setting is empty.

As a result, third-party Autofill services can save passwords in Chrome
if the user does not have any Accessibility services enabled. These
services can reliably check for this situation in the same way as done
in this change and thus selectively offer save flows when they now the
password will be unmasked.

Bug: 1151614
Change-Id: I4644c977f65bf31fa4e1daa76a1e5d55cd0adada
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2552791Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Reviewed-by: default avatarMichael Bai <michaelbai@chromium.org>
Commit-Queue: Fabian Henneke <fabian.henneke@gmail.com>
Cr-Commit-Position: refs/heads/master@{#833473}
parent ff820611
......@@ -1797,10 +1797,37 @@ public class WebContentsAccessibilityImpl extends AccessibilityNodeProvider
event.getText().add(text);
}
boolean isCompatAutofillOnlyPossibleAccessibilityConsumer() {
// Compatibility Autofill is only available on Android P+.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
return false;
}
// The Android Autofill CompatibilityBridge, which is responsible for translating
// Accessibility information to Autofill events, directly hooks into the
// AccessibilityManager via an AccessibilityPolicy rather than by running an
// AccessibilityService. We can thus check whether it is the only consumer of Accessibility
// information by reading the names of active accessibility services from settings.
//
// Note that the CompatibilityBridge makes getEnabledAccessibilityServicesList return a mock
// service to indicate its presence. It is thus easier to read the setting directly than
// to filter out this service from the returned list. Furthermore, since Accessibility is
// only initialized if there is at least one actual service or if Autofill is enabled,
// there is no need to check that Autofill is enabled here.
//
// https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/view/autofill/AutofillManager.java;l=2817;drc=dd7d52f9632a0dbb8b14b69520c5ea31e0b3b4a2
String activeServices = Settings.Secure.getString(
mContext.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
if (activeServices != null && !activeServices.isEmpty()) {
return false;
}
return true;
}
/**
* On Android O and higher, we should respect whatever is displayed
* in a password box and report that via accessibility APIs, whether
* that's the unobscured password, or all dots.
* On Android O and higher, we should respect whatever is displayed in a password box and
* report that via accessibility APIs, whether that's the unobscured password, or all dots.
* However, we deviate from this rule if the only consumer of accessibility information is
* Autofill in order to allow third-party Autofill services to save the real, unmasked password.
*
* Previous to O, shouldExposePasswordText() returns a system setting
* that determines whether we should return the unobscured password or all
......@@ -1808,14 +1835,24 @@ public class WebContentsAccessibilityImpl extends AccessibilityNodeProvider
*/
@CalledByNative
boolean shouldRespectDisplayedPasswordText() {
if (isCompatAutofillOnlyPossibleAccessibilityConsumer()) {
return false;
}
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
}
/**
* Only relevant prior to Android O, see shouldRespectDisplayedPasswordText.
* Only relevant prior to Android O, see shouldRespectDisplayedPasswordText, unless the only
* Accessibility consumer is compatibility Autofill.
*/
@CalledByNative
boolean shouldExposePasswordText() {
// Should always expose the actual password text to Autofill so that third-party Autofill
// services can save it rather than obtain only the masking characters.
if (isCompatAutofillOnlyPossibleAccessibilityConsumer()) {
return true;
}
ContentResolver contentResolver = mContext.getContentResolver();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment