import android.util.LongSparseArray;
import android.util.SparseArray;
+import com.android.internal.util.ArrayUtils;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
}
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.findAccessibilityNodeInfoByAccessibilityId(
- accessibilityWindowId, accessibilityNodeId, interactionId, this,
- prefetchFlags, Thread.currentThread().getId(), arguments);
- Binder.restoreCallingIdentity(identityToken);
- if (success) {
+ final String[] packageNames;
+ try {
+ packageNames = connection.findAccessibilityNodeInfoByAccessibilityId(
+ accessibilityWindowId, accessibilityNodeId, interactionId, this,
+ prefetchFlags, Thread.currentThread().getId(), arguments);
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+ if (packageNames != null) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
- finalizeAndCacheAccessibilityNodeInfos(infos, connectionId);
+ finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
+ bypassCache, packageNames);
if (infos != null && !infos.isEmpty()) {
for (int i = 1; i < infos.size(); i++) {
infos.get(i).recycle();
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.findAccessibilityNodeInfosByViewId(
- accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
- Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
- if (success) {
+ final String[] packageNames;
+ try {
+ packageNames = connection.findAccessibilityNodeInfosByViewId(
+ accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
+ Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
+ if (packageNames != null) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
if (infos != null) {
- finalizeAndCacheAccessibilityNodeInfos(infos, connectionId);
+ finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
+ false, packageNames);
return infos;
}
}
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.findAccessibilityNodeInfosByText(
- accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
- Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
- if (success) {
+ final String[] packageNames;
+ try {
+ packageNames = connection.findAccessibilityNodeInfosByText(
+ accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
+ Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
+ if (packageNames != null) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
if (infos != null) {
- finalizeAndCacheAccessibilityNodeInfos(infos, connectionId);
+ finalizeAndCacheAccessibilityNodeInfos(infos, connectionId,
+ false, packageNames);
return infos;
}
}
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.findFocus(accessibilityWindowId,
- accessibilityNodeId, focusType, interactionId, this,
- Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
- if (success) {
+ final String[] packageNames;
+ try {
+ packageNames = connection.findFocus(accessibilityWindowId,
+ accessibilityNodeId, focusType, interactionId, this,
+ Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
+ if (packageNames != null) {
AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
interactionId);
- finalizeAndCacheAccessibilityNodeInfo(info, connectionId);
+ finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false, packageNames);
return info;
}
} else {
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.focusSearch(accessibilityWindowId,
- accessibilityNodeId, direction, interactionId, this,
- Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
- if (success) {
+ final String[] packageNames;
+ try {
+ packageNames = connection.focusSearch(accessibilityWindowId,
+ accessibilityNodeId, direction, interactionId, this,
+ Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
+ if (packageNames != null) {
AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
interactionId);
- finalizeAndCacheAccessibilityNodeInfo(info, connectionId);
+ finalizeAndCacheAccessibilityNodeInfo(info, connectionId, false, packageNames);
return info;
}
} else {
int interactionId) {
synchronized (mInstanceLock) {
final boolean success = waitForResultTimedLocked(interactionId);
- List<AccessibilityNodeInfo> result = null;
+ final List<AccessibilityNodeInfo> result;
if (success) {
result = mFindAccessibilityNodeInfosResult;
} else {
*
* @param info The info.
* @param connectionId The id of the connection to the system.
+ * @param bypassCache Whether or not to bypass the cache. The node is added to the cache if
+ * this value is {@code false}
+ * @param packageNames The valid package names a node can come from.
*/
private void finalizeAndCacheAccessibilityNodeInfo(AccessibilityNodeInfo info,
- int connectionId) {
+ int connectionId, boolean bypassCache, String[] packageNames) {
if (info != null) {
info.setConnectionId(connectionId);
+ // Empty array means any package name is Okay
+ if (!ArrayUtils.isEmpty(packageNames)
+ && !ArrayUtils.contains(packageNames, info.getPackageName().toString())) {
+ // If the node package not one of the valid ones, pick the top one - this
+ // is one of the packages running in the introspected UID.
+ info.setPackageName(packageNames[0]);
+ }
info.setSealed(true);
- sAccessibilityCache.add(info);
+ if (!bypassCache) {
+ sAccessibilityCache.add(info);
+ }
}
}
*
* @param infos The {@link AccessibilityNodeInfo}s.
* @param connectionId The id of the connection to the system.
+ * @param bypassCache Whether or not to bypass the cache. The nodes are added to the cache if
+ * this value is {@code false}
+ * @param packageNames The valid package names a node can come from.
*/
private void finalizeAndCacheAccessibilityNodeInfos(List<AccessibilityNodeInfo> infos,
- int connectionId) {
+ int connectionId, boolean bypassCache, String[] packageNames) {
if (infos != null) {
final int infosCount = infos.size();
for (int i = 0; i < infosCount; i++) {
AccessibilityNodeInfo info = infos.get(i);
- finalizeAndCacheAccessibilityNodeInfo(info, connectionId);
+ finalizeAndCacheAccessibilityNodeInfo(info, connectionId,
+ bypassCache, packageNames);
}
}
}
import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.app.UiAutomation;
+import android.appwidget.AppWidgetManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.ArraySet;
import android.view.Display;
import android.view.IWindow;
import android.view.InputDevice;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IntPair;
+import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.policy.AccessibilityShortcutController;
import com.android.server.statusbar.StatusBarManagerInternal;
-
+import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileDescriptor;
private final WindowManagerInternal mWindowManagerService;
+ private AppWidgetManagerInternal mAppWidgetService;
+
private final SecurityPolicy mSecurityPolicy;
private final MainHandler mMainHandler;
private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients =
new RemoteCallbackList<>();
- private final SparseArray<AccessibilityConnectionWrapper> mGlobalInteractionConnections =
+ private final SparseArray<RemoteAccessibilityConnection> mGlobalInteractionConnections =
new SparseArray<>();
- private AccessibilityConnectionWrapper mPictureInPictureActionReplacingConnection;
+ private RemoteAccessibilityConnection mPictureInPictureActionReplacingConnection;
private final SparseArray<IBinder> mGlobalWindowTokens = new SparseArray<>();
// performs the current profile parent resolution..
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
+
+ // Make sure the reported package is one the caller has access to.
+ event.setPackageName(mSecurityPolicy.resolveValidReportedPackageLocked(
+ event.getPackageName(), UserHandle.getCallingAppId(), resolvedUserId));
+
// This method does nothing for a background user.
if (resolvedUserId == mCurrentUserId) {
if (mSecurityPolicy.canDispatchAccessibilityEventLocked(event)) {
@Override
public int addAccessibilityInteractionConnection(IWindow windowToken,
- IAccessibilityInteractionConnection connection, int userId) throws RemoteException {
+ IAccessibilityInteractionConnection connection, String packageName,
+ int userId) throws RemoteException {
synchronized (mLock) {
// We treat calls from a profile as if made by its parent as profiles
// share the accessibility state of the parent. The call below
// performs the current profile parent resolution.
final int resolvedUserId = mSecurityPolicy
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
+ final int resolvedUid = UserHandle.getUid(resolvedUserId, UserHandle.getCallingAppId());
+
+ // Make sure the reported package is one the caller has access to.
+ packageName = mSecurityPolicy.resolveValidReportedPackageLocked(
+ packageName, UserHandle.getCallingAppId(), resolvedUserId);
+
final int windowId = sNextWindowId++;
// If the window is from a process that runs across users such as
// the system UI or the system we add it to the global state that
// is shared across users.
if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) {
- AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
- windowId, connection, UserHandle.USER_ALL);
+ RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection(
+ windowId, connection, packageName, resolvedUid, UserHandle.USER_ALL);
wrapper.linkToDeath();
mGlobalInteractionConnections.put(windowId, wrapper);
mGlobalWindowTokens.put(windowId, windowToken.asBinder());
if (DEBUG) {
Slog.i(LOG_TAG, "Added global connection for pid:" + Binder.getCallingPid()
- + " with windowId: " + windowId + " and token: " + windowToken.asBinder());
+ + " with windowId: " + windowId + " and token: "
+ + windowToken.asBinder());
}
} else {
- AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
- windowId, connection, resolvedUserId);
+ RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection(
+ windowId, connection, packageName, resolvedUid, resolvedUserId);
wrapper.linkToDeath();
UserState userState = getUserStateLocked(resolvedUserId);
userState.mInteractionConnections.put(windowId, wrapper);
if (removedWindowId >= 0) {
if (DEBUG) {
Slog.i(LOG_TAG, "Removed global connection for pid:" + Binder.getCallingPid()
- + " with windowId: " + removedWindowId + " and token: " + window.asBinder());
+ + " with windowId: " + removedWindowId + " and token: "
+ + window.asBinder());
}
return;
}
private int removeAccessibilityInteractionConnectionInternalLocked(IBinder windowToken,
SparseArray<IBinder> windowTokens,
- SparseArray<AccessibilityConnectionWrapper> interactionConnections) {
+ SparseArray<RemoteAccessibilityConnection> interactionConnections) {
final int count = windowTokens.size();
for (int i = 0; i < count; i++) {
if (windowTokens.valueAt(i) == windowToken) {
final int windowId = windowTokens.keyAt(i);
windowTokens.removeAt(i);
- AccessibilityConnectionWrapper wrapper = interactionConnections.get(windowId);
+ RemoteAccessibilityConnection wrapper = interactionConnections.get(windowId);
wrapper.unlinkToDeath();
interactionConnections.remove(windowId);
return windowId;
mPictureInPictureActionReplacingConnection = null;
}
if (connection != null) {
- AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(
+ RemoteAccessibilityConnection wrapper = new RemoteAccessibilityConnection(
AccessibilityWindowInfo.PICTURE_IN_PICTURE_ACTION_REPLACER_WINDOW_ID,
- connection, UserHandle.USER_ALL);
+ connection, "foo.bar.baz", Process.SYSTEM_UID, UserHandle.USER_ALL);
mPictureInPictureActionReplacingConnection = wrapper;
wrapper.linkToDeath();
}
final long identity = Binder.clearCallingIdentity();
try {
Settings.Secure.putStringForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null, userState.mUserId);
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null,
+ userState.mUserId);
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 0, userState.mUserId);
}
}
- private class AccessibilityConnectionWrapper implements DeathRecipient {
+ class RemoteAccessibilityConnection implements DeathRecipient {
+ private final int mUid;
+ private final String mPackageName;
private final int mWindowId;
private final int mUserId;
private final IAccessibilityInteractionConnection mConnection;
- public AccessibilityConnectionWrapper(int windowId,
- IAccessibilityInteractionConnection connection, int userId) {
+ RemoteAccessibilityConnection(int windowId,
+ IAccessibilityInteractionConnection connection,
+ String packageName, int uid, int userId) {
mWindowId = windowId;
+ mPackageName = packageName;
+ mUid = uid;
mUserId = userId;
mConnection = connection;
}
+ public int getUid() {
+ return mUid;
+ }
+
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ public IAccessibilityInteractionConnection getRemote() {
+ return mConnection;
+ }
+
public void linkToDeath() throws RemoteException {
mConnection.asBinder().linkToDeath(this, 0);
}
}
@Override
- public boolean findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
+ public String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
long accessibilityNodeId, String viewIdResName, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
throws RemoteException {
final int resolvedWindowId;
- IAccessibilityInteractionConnection connection = null;
+ RemoteAccessibilityConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
MagnificationSpec spec;
synchronized (mLock) {
mUsesAccessibilityCache = true;
if (!isCalledForCurrentUserLocked()) {
- return false;
+ return null;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
if (!permissionGranted) {
- return false;
+ return null;
} else {
connection = getConnectionLocked(resolvedWindowId);
if (connection == null) {
- return false;
+ return null;
}
}
if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
final int interrogatingPid = Binder.getCallingPid();
callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
interrogatingPid, interrogatingTid);
+ final int callingUid = Binder.getCallingUid();
final long identityToken = Binder.clearCallingIdentity();
try {
- connection.findAccessibilityNodeInfosByViewId(accessibilityNodeId, viewIdResName,
- partialInteractiveRegion, interactionId, callback, mFetchFlags,
- interrogatingPid, interrogatingTid, spec);
- return true;
+ connection.getRemote().findAccessibilityNodeInfosByViewId(accessibilityNodeId,
+ viewIdResName, partialInteractiveRegion, interactionId, callback,
+ mFetchFlags, interrogatingPid, interrogatingTid, spec);
+ return mSecurityPolicy.computeValidReportedPackages(callingUid,
+ connection.getPackageName(), connection.getUid());
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
} finally {
Binder.restoreCallingIdentity(identityToken);
// Recycle if passed to another process.
- if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+ if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
partialInteractiveRegion.recycle();
}
}
- return false;
+ return null;
}
@Override
- public boolean findAccessibilityNodeInfosByText(int accessibilityWindowId,
+ public String[] findAccessibilityNodeInfosByText(int accessibilityWindowId,
long accessibilityNodeId, String text, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
throws RemoteException {
final int resolvedWindowId;
- IAccessibilityInteractionConnection connection = null;
+ RemoteAccessibilityConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
MagnificationSpec spec;
synchronized (mLock) {
mUsesAccessibilityCache = true;
if (!isCalledForCurrentUserLocked()) {
- return false;
+ return null;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
if (!permissionGranted) {
- return false;
+ return null;
} else {
connection = getConnectionLocked(resolvedWindowId);
if (connection == null) {
- return false;
+ return null;
}
}
if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
final int interrogatingPid = Binder.getCallingPid();
callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
interrogatingPid, interrogatingTid);
+ final int callingUid = Binder.getCallingUid();
final long identityToken = Binder.clearCallingIdentity();
try {
- connection.findAccessibilityNodeInfosByText(accessibilityNodeId, text,
+ connection.getRemote().findAccessibilityNodeInfosByText(accessibilityNodeId, text,
partialInteractiveRegion, interactionId, callback, mFetchFlags,
interrogatingPid, interrogatingTid, spec);
- return true;
+ return mSecurityPolicy.computeValidReportedPackages(callingUid,
+ connection.getPackageName(), connection.getUid());
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
} finally {
Binder.restoreCallingIdentity(identityToken);
// Recycle if passed to another process.
- if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+ if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
partialInteractiveRegion.recycle();
}
}
- return false;
+ return null;
}
@Override
- public boolean findAccessibilityNodeInfoByAccessibilityId(
+ public String[] findAccessibilityNodeInfoByAccessibilityId(
int accessibilityWindowId, long accessibilityNodeId, int interactionId,
IAccessibilityInteractionConnectionCallback callback, int flags,
long interrogatingTid, Bundle arguments) throws RemoteException {
final int resolvedWindowId;
- IAccessibilityInteractionConnection connection = null;
+ RemoteAccessibilityConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
MagnificationSpec spec;
synchronized (mLock) {
mUsesAccessibilityCache = true;
if (!isCalledForCurrentUserLocked()) {
- return false;
+ return null;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
if (!permissionGranted) {
- return false;
+ return null;
} else {
connection = getConnectionLocked(resolvedWindowId);
if (connection == null) {
- return false;
+ return null;
}
}
if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
final int interrogatingPid = Binder.getCallingPid();
callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
interrogatingPid, interrogatingTid);
+ final int callingUid = Binder.getCallingUid();
final long identityToken = Binder.clearCallingIdentity();
try {
- connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityNodeId,
- partialInteractiveRegion, interactionId, callback, mFetchFlags | flags,
- interrogatingPid, interrogatingTid, spec, arguments);
- return true;
+ connection.getRemote().findAccessibilityNodeInfoByAccessibilityId(
+ accessibilityNodeId, partialInteractiveRegion, interactionId, callback,
+ mFetchFlags | flags, interrogatingPid, interrogatingTid, spec, arguments);
+ return mSecurityPolicy.computeValidReportedPackages(callingUid,
+ connection.getPackageName(), connection.getUid());
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
} finally {
Binder.restoreCallingIdentity(identityToken);
// Recycle if passed to another process.
- if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+ if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
partialInteractiveRegion.recycle();
}
}
- return false;
+ return null;
}
@Override
- public boolean findFocus(int accessibilityWindowId, long accessibilityNodeId,
+ public String[] findFocus(int accessibilityWindowId, long accessibilityNodeId,
int focusType, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
throws RemoteException {
final int resolvedWindowId;
- IAccessibilityInteractionConnection connection = null;
+ RemoteAccessibilityConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
MagnificationSpec spec;
synchronized (mLock) {
if (!isCalledForCurrentUserLocked()) {
- return false;
+ return null;
}
resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked(
accessibilityWindowId, focusType);
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
if (!permissionGranted) {
- return false;
+ return null;
} else {
connection = getConnectionLocked(resolvedWindowId);
if (connection == null) {
- return false;
+ return null;
}
}
if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
final int interrogatingPid = Binder.getCallingPid();
callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
interrogatingPid, interrogatingTid);
+ final int callingUid = Binder.getCallingUid();
final long identityToken = Binder.clearCallingIdentity();
try {
- connection.findFocus(accessibilityNodeId, focusType, partialInteractiveRegion,
- interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
- spec);
- return true;
+ connection.getRemote().findFocus(accessibilityNodeId, focusType,
+ partialInteractiveRegion, interactionId, callback, mFetchFlags,
+ interrogatingPid, interrogatingTid, spec);
+ return mSecurityPolicy.computeValidReportedPackages(callingUid,
+ connection.getPackageName(), connection.getUid());
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling findFocus()");
} finally {
Binder.restoreCallingIdentity(identityToken);
// Recycle if passed to another process.
- if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+ if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
partialInteractiveRegion.recycle();
}
}
- return false;
+ return null;
}
@Override
- public boolean focusSearch(int accessibilityWindowId, long accessibilityNodeId,
+ public String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId,
int direction, int interactionId,
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
throws RemoteException {
final int resolvedWindowId;
- IAccessibilityInteractionConnection connection = null;
+ RemoteAccessibilityConnection connection = null;
Region partialInteractiveRegion = Region.obtain();
MagnificationSpec spec;
synchronized (mLock) {
if (!isCalledForCurrentUserLocked()) {
- return false;
+ return null;
}
resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, resolvedWindowId);
if (!permissionGranted) {
- return false;
+ return null;
} else {
connection = getConnectionLocked(resolvedWindowId);
if (connection == null) {
- return false;
+ return null;
}
}
if (!mSecurityPolicy.computePartialInteractiveRegionForWindowLocked(
final int interrogatingPid = Binder.getCallingPid();
callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
interrogatingPid, interrogatingTid);
+ final int callingUid = Binder.getCallingUid();
final long identityToken = Binder.clearCallingIdentity();
try {
- connection.focusSearch(accessibilityNodeId, direction, partialInteractiveRegion,
- interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid,
- spec);
- return true;
+ connection.getRemote().focusSearch(accessibilityNodeId, direction,
+ partialInteractiveRegion, interactionId, callback, mFetchFlags,
+ interrogatingPid, interrogatingTid, spec);
+ return mSecurityPolicy.computeValidReportedPackages(callingUid,
+ connection.getPackageName(), connection.getUid());
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()");
} finally {
Binder.restoreCallingIdentity(identityToken);
// Recycle if passed to another process.
- if (partialInteractiveRegion != null && Binder.isProxy(connection)) {
+ if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
partialInteractiveRegion.recycle();
}
}
- return false;
+ return null;
}
@Override
IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
throws RemoteException {
final int resolvedWindowId;
- IAccessibilityInteractionConnection connection = null;
IBinder activityToken = null;
+ RemoteAccessibilityConnection connection;
synchronized (mLock) {
if (!isCalledForCurrentUserLocked()) {
return false;
if ((a11yWindowInfo != null) && a11yWindowInfo.inPictureInPicture()) {
if ((mPictureInPictureActionReplacingConnection != null)
&& !isA11yFocusAction) {
- connection = mPictureInPictureActionReplacingConnection.mConnection;
+ connection = mPictureInPictureActionReplacingConnection;
}
}
}
LocalServices.getService(ActivityManagerInternal.class)
.setFocusedActivity(activityToken);
}
- connection.performAccessibilityAction(accessibilityNodeId, action, arguments,
- interactionId, callback, mFetchFlags, interrogatingPid, interrogatingTid);
+ connection.mConnection.performAccessibilityAction(accessibilityNodeId, action,
+ arguments, interactionId, callback, mFetchFlags, interrogatingPid,
+ interrogatingTid);
} catch (RemoteException re) {
if (DEBUG) {
Slog.e(LOG_TAG, "Error calling performAccessibilityAction()");
LocalServices.getService(StatusBarManagerInternal.class).toggleSplitScreen();
}
- private IAccessibilityInteractionConnection getConnectionLocked(int windowId) {
+ private RemoteAccessibilityConnection getConnectionLocked(int windowId) {
if (DEBUG) {
Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId);
}
- AccessibilityConnectionWrapper wrapper = mGlobalInteractionConnections.get(windowId);
+ RemoteAccessibilityConnection wrapper = mGlobalInteractionConnections.get(windowId);
if (wrapper == null) {
wrapper = getCurrentUserStateLocked().mInteractionConnections.get(windowId);
}
if (wrapper != null && wrapper.mConnection != null) {
- return wrapper.mConnection;
+ return wrapper;
}
if (DEBUG) {
Slog.e(LOG_TAG, "No interaction connection to window: " + windowId);
}
}
+ private AppWidgetManagerInternal getAppWidgetManager() {
+ synchronized (mLock) {
+ if (mAppWidgetService == null
+ && mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
+ mAppWidgetService = LocalServices.getService(AppWidgetManagerInternal.class);
+ }
+ return mAppWidgetService;
+ }
+ }
+
final class WindowsForAccessibilityCallback implements
WindowManagerInternal.WindowsForAccessibilityCallback {
}
}
+ private boolean isValidPackageForUid(String packageName, int uid) {
+ try {
+ return uid == mPackageManager.getPackageUid(
+ packageName, UserHandle.getUserId(uid));
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ String resolveValidReportedPackageLocked(CharSequence packageName, int appId, int userId) {
+ // Okay to pass no package
+ if (packageName == null) {
+ return null;
+ }
+ // The system gets to pass any package
+ if (appId == Process.SYSTEM_UID) {
+ return packageName.toString();
+ }
+ // Passing a package in your UID is fine
+ final String packageNameStr = packageName.toString();
+ final int resolvedUid = UserHandle.getUid(userId, appId);
+ if (isValidPackageForUid(packageNameStr, resolvedUid)) {
+ return packageName.toString();
+ }
+ // Appwidget hosts get to pass packages for widgets they host
+ final AppWidgetManagerInternal appWidgetManager = getAppWidgetManager();
+ if (appWidgetManager != null && ArrayUtils.contains(appWidgetManager
+ .getHostedWidgetPackages(resolvedUid), packageNameStr)) {
+ return packageName.toString();
+ }
+ // Otherwise, set the package to the first one in the UID
+ final String[] packageNames = mPackageManager.getPackagesForUid(resolvedUid);
+ if (ArrayUtils.isEmpty(packageNames)) {
+ return null;
+ }
+ // Okay, the caller reported a package it does not have access to.
+ // Instead of crashing the caller for better backwards compatibility
+ // we report the first package in the UID. Since most of the time apps
+ // don't use shared user id, this will yield correct results and for
+ // the edge case of using a shared user id we may report the wrong
+ // package but this is fine since first, this is a cheating app and
+ // second there is no way to get the correct package anyway.
+ return packageNames[0];
+ }
+
+ String[] computeValidReportedPackages(int callingUid,
+ String targetPackage, int targetUid) {
+ if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
+ // Empty array means any package is Okay
+ return EmptyArray.STRING;
+ }
+ // IMPORTANT: The target package is already vetted to be in the target UID
+ String[] uidPackages = new String[]{targetPackage};
+ // Appwidget hosts get to pass packages for widgets they host
+ final AppWidgetManagerInternal appWidgetManager = getAppWidgetManager();
+ if (appWidgetManager != null) {
+ final ArraySet<String> widgetPackages = appWidgetManager
+ .getHostedWidgetPackages(targetUid);
+ if (widgetPackages != null && !widgetPackages.isEmpty()) {
+ final String[] validPackages = new String[uidPackages.length
+ + widgetPackages.size()];
+ System.arraycopy(uidPackages, 0, validPackages, 0, uidPackages.length);
+ final int widgetPackageCount = widgetPackages.size();
+ for (int i = 0; i < widgetPackageCount; i++) {
+ validPackages[uidPackages.length + i] = widgetPackages.valueAt(i);
+ }
+ return validPackages;
+ }
+ }
+ return uidPackages;
+ }
+
public void clearWindowsLocked() {
List<WindowInfo> windows = Collections.emptyList();
final int activeWindowId = mActiveWindowId;
public final RemoteCallbackList<IAccessibilityManagerClient> mUserClients =
new RemoteCallbackList<>();
- public final SparseArray<AccessibilityConnectionWrapper> mInteractionConnections =
+ public final SparseArray<RemoteAccessibilityConnection> mInteractionConnections =
new SparseArray<>();
public final SparseArray<IBinder> mWindowTokens = new SparseArray<>();