Merge "Fix deadlock regarding screen-capture-disabled" into pi-dev

This commit is contained in:
Makoto Onuki
2018-03-15 21:01:49 +00:00
committed by Android (Google) Code Review
8 changed files with 149 additions and 68 deletions

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.admin;
import android.annotation.UserIdInt;
import com.android.server.LocalServices;
/**
* Stores a copy of the set of device policies maintained by {@link DevicePolicyManager} that
* can be accessed from any place without risking dead locks.
*
* @hide
*/
public abstract class DevicePolicyCache {
protected DevicePolicyCache() {
}
/**
* @return the instance.
*/
public static DevicePolicyCache getInstance() {
final DevicePolicyManagerInternal dpmi =
LocalServices.getService(DevicePolicyManagerInternal.class);
return (dpmi != null) ? dpmi.getDevicePolicyCache() : EmptyDevicePolicyCache.INSTANCE;
}
/**
* See {@link DevicePolicyManager#getScreenCaptureDisabled}
*/
public abstract boolean getScreenCaptureDisabled(@UserIdInt int userHandle);
/**
* Empty implementation.
*/
private static class EmptyDevicePolicyCache extends DevicePolicyCache {
private static final EmptyDevicePolicyCache INSTANCE = new EmptyDevicePolicyCache();
@Override
public boolean getScreenCaptureDisabled(int userHandle) {
return false;
}
}
}

View File

@@ -141,4 +141,10 @@ public abstract class DevicePolicyManagerInternal {
* @return localized error message
*/
public abstract CharSequence getPrintingDisabledReasonForUser(@UserIdInt int userId);
/**
* @return cached version of DPM policies that can be accessed without risking deadlocks.
* Do not call it directly. Use {@link DevicePolicyCache#getInstance()} instead.
*/
protected abstract DevicePolicyCache getDevicePolicyCache();
}

View File

@@ -181,9 +181,10 @@ interface IWindowManager
void setStrictModeVisualIndicatorPreference(String enabled);
/**
* Set whether screen capture is disabled for all windows of a specific user
* Set whether screen capture is disabled for all windows of a specific user from
* the device policy cache.
*/
void setScreenCaptureDisabled(int userId, boolean disabled);
void refreshScreenCaptureDisabled(int userId);
// These can only be called with the SET_ORIENTATION permission.
/**

View File

@@ -256,6 +256,7 @@ import android.app.RemoteAction;
import android.app.WaitResult;
import android.app.WindowConfiguration.ActivityType;
import android.app.WindowConfiguration.WindowingMode;
import android.app.admin.DevicePolicyCache;
import android.app.admin.DevicePolicyManager;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
@@ -13727,9 +13728,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
userId = activity.userId;
}
DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
Context.DEVICE_POLICY_SERVICE);
return (dpm == null) || (!dpm.getScreenCaptureDisabled(null, userId));
return !DevicePolicyCache.getInstance().getScreenCaptureDisabled(userId);
}
@Override

View File

@@ -25,7 +25,6 @@ import static android.app.ActivityManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.StatusBarManager.DISABLE_MASK;
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_USER_HANDLE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;
@@ -122,6 +121,7 @@ import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.IAssistDataReceiver;
import android.app.admin.DevicePolicyCache;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -380,14 +380,6 @@ public class WindowManagerService extends IWindowManager.Stub
case ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED:
mKeyguardDisableHandler.sendEmptyMessage(KEYGUARD_POLICY_CHANGED);
break;
case ACTION_USER_REMOVED:
final int userId = intent.getIntExtra(EXTRA_USER_HANDLE, USER_NULL);
if (userId != USER_NULL) {
synchronized (mWindowMap) {
mScreenCaptureDisabled.remove(userId);
}
}
break;
}
}
};
@@ -519,13 +511,6 @@ public class WindowManagerService extends IWindowManager.Stub
/** List of window currently causing non-system overlay windows to be hidden. */
private ArrayList<WindowState> mHidingNonSystemOverlayWindows = new ArrayList<>();
/**
* Stores for each user whether screencapture is disabled
* This array is essentially a cache for all userId for
* {@link android.app.admin.DevicePolicyManager#getScreenCaptureDisabled}
*/
private SparseArray<Boolean> mScreenCaptureDisabled = new SparseArray<>();
IInputMethodManager mInputMethodManager;
AccessibilityController mAccessibilityController;
@@ -1039,8 +1024,6 @@ public class WindowManagerService extends IWindowManager.Stub
IntentFilter filter = new IntentFilter();
// Track changes to DevicePolicyManager state so we can enable/disable keyguard.
filter.addAction(ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
// Listen to user removal broadcasts so that we can remove the user-specific data.
filter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiver(mBroadcastReceiver, filter);
mLatencyTracker = LatencyTracker.getInstance(context);
@@ -1572,41 +1555,32 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
/**
* Returns whether screen capture is disabled for all windows of a specific user.
*/
boolean isScreenCaptureDisabledLocked(int userId) {
Boolean disabled = mScreenCaptureDisabled.get(userId);
if (disabled == null) {
return false;
}
return disabled;
}
boolean isSecureLocked(WindowState w) {
if ((w.mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
return true;
}
if (isScreenCaptureDisabledLocked(UserHandle.getUserId(w.mOwnerUid))) {
if (DevicePolicyCache.getInstance().getScreenCaptureDisabled(
UserHandle.getUserId(w.mOwnerUid))) {
return true;
}
return false;
}
/**
* Set mScreenCaptureDisabled for specific user
* Set whether screen capture is disabled for all windows of a specific user from
* the device policy cache.
*/
@Override
public void setScreenCaptureDisabled(int userId, boolean disabled) {
public void refreshScreenCaptureDisabled(int userId) {
int callingUid = Binder.getCallingUid();
if (callingUid != SYSTEM_UID) {
throw new SecurityException("Only system can call setScreenCaptureDisabled.");
throw new SecurityException("Only system can call refreshScreenCaptureDisabled.");
}
synchronized(mWindowMap) {
mScreenCaptureDisabled.put(userId, disabled);
// Update secure surface for all windows belonging to this user.
mRoot.setSecureSurfaceState(userId, disabled);
mRoot.setSecureSurfaceState(userId,
DevicePolicyCache.getInstance().getScreenCaptureDisabled(userId));
}
}

View File

@@ -70,8 +70,6 @@ public class WindowManagerShellCommand extends ShellCommand {
return runDisplayOverscan(pw);
case "scaling":
return runDisplayScaling(pw);
case "screen-capture":
return runSetScreenCapture(pw);
case "dismiss-keyguard":
return runDismissKeyguard(pw);
case "tracing":
@@ -210,24 +208,6 @@ public class WindowManagerShellCommand extends ShellCommand {
return 0;
}
private int runSetScreenCapture(PrintWriter pw) throws RemoteException {
String userIdStr = getNextArg();
String enableStr = getNextArg();
int userId;
boolean disable;
try {
userId = Integer.parseInt(userIdStr);
} catch (NumberFormatException e) {
getErrPrintWriter().println("Error: bad number " + e);
return -1;
}
disable = !Boolean.parseBoolean(enableStr);
mInternal.setScreenCaptureDisabled(userId, disable);
return 0;
}
private int runDismissKeyguard(PrintWriter pw) throws RemoteException {
mInterface.dismissKeyguard(null /* callback */, null /* message */);
return 0;
@@ -265,8 +245,6 @@ public class WindowManagerShellCommand extends ShellCommand {
pw.println(" Set overscan area for display.");
pw.println(" scaling [off|auto]");
pw.println(" Set display scaling mode.");
pw.println(" screen-capture [userId] [true|false]");
pw.println(" Enable or disable screen capture.");
pw.println(" dismiss-keyguard");
pw.println(" Dismiss the keyguard, prompting user for auth if necessary.");
if (!IS_USER) {

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.devicepolicy;
import android.app.admin.DevicePolicyCache;
import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
/**
* Implementation of {@link DevicePolicyCache}, to which {@link DevicePolicyManagerService} pushes
* policies.
*
* TODO Move other copies of policies into this class too.
*/
public class DevicePolicyCacheImpl extends DevicePolicyCache {
/**
* Lock object. For simplicity we just always use this as the lock. We could use each object
* as a lock object to make it more fine-grained, but that'd make copy-paste error-prone.
*/
private final Object mLock = new Object();
@GuardedBy("mLock")
private final SparseBooleanArray mScreenCaptureDisabled = new SparseBooleanArray();
public void onUserRemoved(int userHandle) {
synchronized (mLock) {
mScreenCaptureDisabled.delete(userHandle);
}
}
@Override
public boolean getScreenCaptureDisabled(int userHandle) {
synchronized (mLock) {
return mScreenCaptureDisabled.get(userHandle);
}
}
public void setScreenCaptureDisabled(int userHandle, boolean disabled) {
synchronized (mLock) {
mScreenCaptureDisabled.put(userHandle, disabled);
}
}
}

View File

@@ -98,6 +98,7 @@ import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyCache;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.NetworkEvent;
@@ -436,6 +437,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private final DeviceAdminServiceController mDeviceAdminServiceController;
private final OverlayPackagesProvider mOverlayPackagesProvider;
private final DevicePolicyCacheImpl mPolicyCache = new DevicePolicyCacheImpl();
/**
* Contains (package-user) pairs to remove. An entry (p, u) implies that removal of package p
* is requested for user u.
@@ -2176,6 +2179,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring.");
return;
}
mPolicyCache.onUserRemoved(userHandle);
mOwners.removeProfileOwner(userHandle);
mOwners.writeProfileOwner(userHandle);
@@ -2188,7 +2193,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
policyFile.delete();
Slog.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath());
}
updateScreenCaptureDisabledInWindowManager(userHandle, false /* default value */);
}
void loadOwners() {
@@ -3395,7 +3399,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
void handleStartUser(int userId) {
updateScreenCaptureDisabledInWindowManager(userId,
updateScreenCaptureDisabled(userId,
getScreenCaptureDisabled(null, userId));
pushUserRestrictions(userId);
@@ -6632,7 +6636,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (ap.disableScreenCapture != disabled) {
ap.disableScreenCapture = disabled;
saveSettingsLocked(userHandle);
updateScreenCaptureDisabledInWindowManager(userHandle, disabled);
updateScreenCaptureDisabled(userHandle, disabled);
}
}
}
@@ -6664,13 +6668,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
private void updateScreenCaptureDisabledInWindowManager(final int userHandle,
final boolean disabled) {
private void updateScreenCaptureDisabled(int userHandle, boolean disabled) {
mPolicyCache.setScreenCaptureDisabled(userHandle, disabled);
mHandler.post(new Runnable() {
@Override
public void run() {
try {
mInjector.getIWindowManager().setScreenCaptureDisabled(userHandle, disabled);
mInjector.getIWindowManager().refreshScreenCaptureDisabled(userHandle);
} catch (RemoteException e) {
Log.w(LOG_TAG, "Unable to notify WindowManager.", e);
}
@@ -10502,6 +10506,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
.getResources().getString(R.string.printing_disabled_by, appLabel);
}
}
@Override
protected DevicePolicyCache getDevicePolicyCache() {
return mPolicyCache;
}
}
private Intent createShowAdminSupportIntent(ComponentName admin, int userId) {