App ops: track system windows, monitoring changes.
Change-Id: I273e82bdad66ada3bf0f7ec9176bc304b9ee1ee8
diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java
index 748b3cb..e94d03c 100644
--- a/services/java/com/android/server/AppOpsService.java
+++ b/services/java/com/android/server/AppOpsService.java
@@ -25,6 +25,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import android.app.AppOpsManager;
@@ -34,7 +35,9 @@
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.AtomicFile;
@@ -45,6 +48,7 @@
import android.util.Xml;
import com.android.internal.app.IAppOpsService;
+import com.android.internal.app.IAppOpsCallback;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
@@ -82,7 +86,7 @@
final SparseArray<HashMap<String, Ops>> mUidOps
= new SparseArray<HashMap<String, Ops>>();
- final static class Ops extends SparseArray<Op> {
+ public final static class Ops extends SparseArray<Op> {
public final String packageName;
public final int uid;
@@ -92,7 +96,7 @@
}
}
- final static class Op {
+ public final static class Op {
public final int op;
public int mode;
public int duration;
@@ -106,6 +110,34 @@
}
}
+ final SparseArray<ArrayList<Callback>> mOpModeWatchers
+ = new SparseArray<ArrayList<Callback>>();
+ final HashMap<String, ArrayList<Callback>> mPackageModeWatchers
+ = new HashMap<String, ArrayList<Callback>>();
+ final HashMap<IBinder, Callback> mModeWatchers
+ = new HashMap<IBinder, Callback>();
+
+ public final class Callback implements DeathRecipient {
+ final IAppOpsCallback mCallback;
+
+ public Callback(IAppOpsCallback callback) {
+ mCallback = callback;
+ try {
+ mCallback.asBinder().linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ }
+ }
+
+ public void unlinkToDeath() {
+ mCallback.asBinder().unlinkToDeath(this, 0);
+ }
+
+ @Override
+ public void binderDied() {
+ stopWatchingMode(mCallback);
+ }
+ }
+
public AppOpsService(File storagePath) {
mFile = new AtomicFile(storagePath);
mHandler = new Handler();
@@ -205,15 +237,94 @@
public void setMode(int code, int uid, String packageName, int mode) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
+ ArrayList<Callback> repCbs = null;
+ code = AppOpsManager.opToSwitch(code);
synchronized (this) {
- Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, true);
+ Op op = getOpLocked(code, uid, packageName, true);
if (op != null) {
if (op.mode != mode) {
op.mode = mode;
+ ArrayList<Callback> cbs = mOpModeWatchers.get(code);
+ if (cbs != null) {
+ if (repCbs == null) {
+ repCbs = new ArrayList<Callback>();
+ }
+ repCbs.addAll(cbs);
+ }
+ cbs = mPackageModeWatchers.get(packageName);
+ if (cbs != null) {
+ if (repCbs == null) {
+ repCbs = new ArrayList<Callback>();
+ }
+ repCbs.addAll(cbs);
+ }
scheduleWriteNowLocked();
}
}
}
+ if (repCbs != null) {
+ for (int i=0; i<repCbs.size(); i++) {
+ try {
+ repCbs.get(i).mCallback.opChanged(code, packageName);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+
+ @Override
+ public void startWatchingMode(int op, String packageName, IAppOpsCallback callback) {
+ synchronized (this) {
+ op = AppOpsManager.opToSwitch(op);
+ Callback cb = mModeWatchers.get(callback.asBinder());
+ if (cb == null) {
+ cb = new Callback(callback);
+ mModeWatchers.put(callback.asBinder(), cb);
+ }
+ if (op != AppOpsManager.OP_NONE) {
+ ArrayList<Callback> cbs = mOpModeWatchers.get(op);
+ if (cbs == null) {
+ cbs = new ArrayList<Callback>();
+ mOpModeWatchers.put(op, cbs);
+ }
+ cbs.add(cb);
+ }
+ if (packageName != null) {
+ ArrayList<Callback> cbs = mPackageModeWatchers.get(packageName);
+ if (cbs == null) {
+ cbs = new ArrayList<Callback>();
+ mPackageModeWatchers.put(packageName, cbs);
+ }
+ cbs.add(cb);
+ }
+ }
+ }
+
+ @Override
+ public void stopWatchingMode(IAppOpsCallback callback) {
+ synchronized (this) {
+ Callback cb = mModeWatchers.remove(callback.asBinder());
+ if (cb != null) {
+ cb.unlinkToDeath();
+ for (int i=0; i<mOpModeWatchers.size(); i++) {
+ ArrayList<Callback> cbs = mOpModeWatchers.valueAt(i);
+ cbs.remove(cb);
+ if (cbs.size() <= 0) {
+ mOpModeWatchers.removeAt(i);
+ }
+ }
+ if (mPackageModeWatchers.size() > 0) {
+ Iterator<ArrayList<Callback>> it = mPackageModeWatchers.values().iterator();
+ while (it.hasNext()) {
+ ArrayList<Callback> cbs = it.next();
+ cbs.remove(cb);
+ if (cbs.size() <= 0) {
+ it.remove();
+ }
+ }
+ }
+ }
+ }
}
@Override
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 62f9965..78699fb 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -221,6 +221,16 @@
mBlacklist.init();
mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
+ // Monitor for app ops mode changes.
+ AppOpsManager.Callback callback = new AppOpsManager.Callback() {
+ public void opChanged(int op, String packageName) {
+ synchronized (mLock) {
+ applyAllProviderRequirementsLocked();
+ }
+ }
+ };
+ mAppOps.startWatchingMode(AppOpsManager.OP_COARSE_LOCATION, null, callback);
+
// prepare providers
loadProvidersLocked();
updateProvidersLocked();
@@ -1335,6 +1345,17 @@
}
}
+ private void applyAllProviderRequirementsLocked() {
+ for (LocationProviderInterface p : mProviders) {
+ // If provider is already disabled, don't need to do anything
+ if (!isAllowedBySettingsLocked(p.getName(), UserHandle.getUid(mCurrentUserId, 0))) {
+ continue;
+ }
+
+ applyRequirementsLocked(p.getName());
+ }
+ }
+
@Override
public Location getLastLocation(LocationRequest request, String packageName) {
if (D) Log.d(TAG, "getLastLocation: " + request);
diff --git a/services/java/com/android/server/VibratorService.java b/services/java/com/android/server/VibratorService.java
index 9065525..21d3111 100644
--- a/services/java/com/android/server/VibratorService.java
+++ b/services/java/com/android/server/VibratorService.java
@@ -466,7 +466,7 @@
//synchronized (mInputDeviceVibrators) {
// return !mInputDeviceVibrators.isEmpty() || vibratorExists();
//}
- return true || vibratorExists();
+ return vibratorExists();
}
private void doVibratorOn(long millis, int uid) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 1e5cd54..4409762 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -42,6 +42,7 @@
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import android.app.AppOpsManager;
import com.android.internal.app.IBatteryStats;
import com.android.internal.policy.PolicyManager;
import com.android.internal.policy.impl.PhoneWindowManager;
@@ -311,6 +312,8 @@
final IBatteryStats mBatteryStats;
+ final AppOpsManager mAppOps;
+
/**
* All currently active sessions with clients.
*/
@@ -765,6 +768,7 @@
mActivityManager = ActivityManagerNative.getDefault();
mBatteryStats = BatteryStatsService.getService();
+ mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
// Get persisted window scale setting
mWindowAnimationScale = Settings.Global.getFloat(context.getContentResolver(),
@@ -2024,7 +2028,8 @@
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, InputChannel outInputChannel) {
- int res = mPolicy.checkAddPermission(attrs);
+ int[] appOp = new int[1];
+ int res = mPolicy.checkAddPermission(attrs, appOp);
if (res != WindowManagerGlobal.ADD_OKAY) {
return res;
}
@@ -2128,7 +2133,7 @@
}
win = new WindowState(this, session, client, token,
- attachedWindow, seq, attrs, viewVisibility, displayContent);
+ attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
if (win.mDeathRecipient == null) {
// Client has apparently died, so there is no reason to
// continue.
@@ -2166,6 +2171,9 @@
}
win.attach();
mWindowMap.put(client.asBinder(), win);
+ if (win.mAppOp != AppOpsManager.OP_NONE) {
+ mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(), win.getOwningPackage());
+ }
if (type == TYPE_APPLICATION_STARTING && token.appWindowToken != null) {
token.appWindowToken.startingWindow = win;
@@ -2376,6 +2384,9 @@
if (DEBUG_ADD_REMOVE) Slog.v(TAG, "removeWindowInnerLocked: " + win);
mWindowMap.remove(win.mClient.asBinder());
+ if (win.mAppOp != AppOpsManager.OP_NONE) {
+ mAppOps.finishOp(win.mAppOp, win.getOwningUid(), win.getOwningPackage());
+ }
final WindowList windows = win.getWindowList();
windows.remove(win);
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index a335958..6648e56 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -24,6 +24,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import android.app.AppOpsManager;
import com.android.server.input.InputWindowHandle;
import android.content.Context;
@@ -69,6 +70,9 @@
final Context mContext;
final Session mSession;
final IWindow mClient;
+ final int mAppOp;
+ // UserId and appId of the owner. Don't display windows of non-current user.
+ final int mOwnerUid;
WindowToken mToken;
WindowToken mRootToken;
AppWindowToken mAppToken;
@@ -270,18 +274,16 @@
DisplayContent mDisplayContent;
- // UserId and appId of the owner. Don't display windows of non-current user.
- int mOwnerUid;
-
/** When true this window can be displayed on screens owther than mOwnerUid's */
private boolean mShowToOwnerOnly;
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
- WindowState attachedWindow, int seq, WindowManager.LayoutParams a,
+ WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
int viewVisibility, final DisplayContent displayContent) {
mService = service;
mSession = s;
mClient = c;
+ mAppOp = appOp;
mToken = token;
mOwnerUid = s.mUid;
mAttrs.copyFrom(a);
@@ -383,7 +385,7 @@
@Override
public int getOwningUid() {
- return mSession.mUid;
+ return mOwnerUid;
}
@Override
@@ -1129,7 +1131,9 @@
pw.print(" mSession="); pw.print(mSession);
pw.print(" mClient="); pw.println(mClient.asBinder());
pw.print(prefix); pw.print("mOwnerUid="); pw.print(mOwnerUid);
- pw.print(" mShowToOwnerOnly="); pw.println(mShowToOwnerOnly);
+ pw.print(" mShowToOwnerOnly="); pw.print(mShowToOwnerOnly);
+ pw.print(" package="); pw.print(mAttrs.packageName);
+ pw.print(" appop="); pw.println(AppOpsManager.opToName(mAppOp));
pw.print(prefix); pw.print("mAttrs="); pw.println(mAttrs);
pw.print(prefix); pw.print("Requested w="); pw.print(mRequestedWidth);
pw.print(" h="); pw.print(mRequestedHeight);
@@ -1273,9 +1277,12 @@
@Override
public String toString() {
- if (mStringNameCache == null || mLastTitle != mAttrs.getTitle()
- || mWasExiting != mExiting) {
- mLastTitle = mAttrs.getTitle();
+ CharSequence title = mAttrs.getTitle();
+ if (title == null || title.length() <= 0) {
+ title = mAttrs.packageName;
+ }
+ if (mStringNameCache == null || mLastTitle != title || mWasExiting != mExiting) {
+ mLastTitle = title;
mWasExiting = mExiting;
mStringNameCache = "Window{" + Integer.toHexString(System.identityHashCode(this))
+ " u" + UserHandle.getUserId(mSession.mUid)