Loading core/java/android/app/AppOpsManager.java +51 −0 Original line number Original line Diff line number Diff line /* /* * Copyright (c) 2013, The Linux Foundation. All rights reserved. * Not a Contribution. * * Copyright (C) 2012 The Android Open Source Project * Copyright (C) 2012 The Android Open Source Project * * * Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License"); Loading Loading @@ -59,6 +62,7 @@ public class AppOpsManager { public static final int MODE_ALLOWED = 0; public static final int MODE_ALLOWED = 0; public static final int MODE_IGNORED = 1; public static final int MODE_IGNORED = 1; public static final int MODE_ERRORED = 2; public static final int MODE_ERRORED = 2; public static final int MODE_ASK = 3; // when adding one of these: // when adding one of these: // - increment _NUM_OP // - increment _NUM_OP Loading Loading @@ -99,6 +103,46 @@ public class AppOpsManager { /** @hide */ /** @hide */ public static final int _NUM_OP = 31; public static final int _NUM_OP = 31; /** * Map to check if each operation is strict or not, to determine default * value of each operation. * If strict then AppOpsService should assign MODE_ASK value to operation * by default. */ private static boolean[] sOpStrict = new boolean[] { true, //OP_COARSE_LOCATION true, //OP_FINE_LOCATION true, //OP_GPS false, //OP_VIBRATE true, //OP_READ_CONTACTS true, //OP_WRITE_CONTACTS true, //OP_READ_CALL_LOG true, //OP_WRITE_CALL_LOG false, //OP_READ_CALENDAR false, //OP_WRITE_CALENDAR true, //OP_WIFI_SCAN false, //OP_POST_NOTIFICATION false, //OP_NEIGHBORING_CELLS true, //OP_CALL_PHONE true, //OP_READ_SMS true, //OP_WRITE_SMS true, //OP_RECEIVE_SMS false, //OP_RECEIVE_EMERGECY_SMS true, //OP_RECEIVE_MMS false, //OP_RECEIVE_WAP_PUSH true, //OP_SEND_SMS true, //OP_READ_ICC_SMS true, //OP_WRITE_ICC_SMS false, //OP_WRITE_SETTINGS false, //OP_SYSTEM_ALERT_WINDOW false, //OP_ACCESS_NOTIFICATIONS true, //OP_CAMERA true, //OP_RECORD_AUDIO true, //OP_PLAY_AUDIO false, //OP_READ_CLIPBOARD false, //OP_WRITE_CLIPBOARD }; /** /** * This maps each operation to the operation that serves as the * This maps each operation to the operation that serves as the * switch to determine whether it is allowed. Generally this is * switch to determine whether it is allowed. Generally this is Loading Loading @@ -217,6 +261,13 @@ public class AppOpsManager { null, // no permission for writing clipboard null, // no permission for writing clipboard }; }; /** * Check if given operation is strict or not. */ public static boolean opStrict(int op) { return sOpStrict[op]; } /** /** * Retrieve the op switch that controls the given operation. * Retrieve the op switch that controls the given operation. */ */ Loading core/res/res/layout/permission_confirmation_dialog.xml 0 → 100644 +46 −0 Original line number Original line Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- /* ** Copyright (c) 2013, The Linux Foundation. All rights reserved. ** Not a Contribution. ** ** Copyright 2012 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. */ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/parentPanel" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="8dip" android:layout_marginRight="8dip" android:orientation="vertical"> <TextView android:id="@+id/permission_text" style="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="20dip" android:paddingRight="20dip" android:paddingTop="16dip" android:paddingBottom="16dip" /> <CheckBox android:id="@+id/permission_remember_choice_checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/save_password_remember" /> </LinearLayout> core/res/res/values/cm_arrays.xml +34 −0 Original line number Original line Diff line number Diff line Loading @@ -52,4 +52,38 @@ <item>2</item> <item>2</item> </string-array> </string-array> <!-- User display names for app ops codes --> <string-array name="app_ops_labels"> <item>Trying to access location</item> <item>Trying to access location</item> <item>Trying to access location</item> <item>Trying to use vibrate</item> <item>Trying to read contacts</item> <item>Trying to modify contacts</item> <item>Trying to read call log</item> <item>Trying to modify call log</item> <item>Trying to read calendar</item> <item>Trying to modify calendar</item> <item>Trying to access location</item> <item>Trying to post notification</item> <item>Trying to access location</item> <item>Trying to make phone call</item> <item>Trying to read SMS/MMS</item> <item>Trying to write/modify SMS/MMS</item> <item>Trying to receive SMS/MMS</item> <item>Trying to receive SMS/MMS</item> <item>Trying to receive SMS/MMS</item> <item>Trying to receive SMS/MMS</item> <item>Trying to send SMS/MMS</item> <item>Trying to read SMS/MMS</item> <item>Trying to write/modify SMS/MMS</item> <item>Trying to modify settings</item> <item>Trying to draw on top</item> <item>Trying to access notifications</item> <item>Trying to access Camera</item> <item>Trying to record audio</item> <item>Trying to play audio</item> <item>Trying to read clipboard</item> <item>Trying to modify clipboard</item> </string-array> </resources> </resources> core/res/res/values/symbols.xml +11 −1 Original line number Original line Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?> <!-- <!-- /* Copyright 2012, The Android Open Source Project /* Copyright (c) 2013, The Linux Foundation. All rights reserved. ** Not a Contribution. ** ** Copyright 2012, The Android Open Source Project ** ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** you may not use this file except in compliance with the License. Loading Loading @@ -218,6 +221,8 @@ <java-symbol type="id" name="sms_short_code_remember_undo_instruction" /> <java-symbol type="id" name="sms_short_code_remember_undo_instruction" /> <java-symbol type="id" name="breadcrumb_section" /> <java-symbol type="id" name="breadcrumb_section" /> <java-symbol type="id" name="action_bar_spinner" /> <java-symbol type="id" name="action_bar_spinner" /> <java-symbol type="id" name="permission_text" /> <java-symbol type="id" name="permission_remember_choice_checkbox" /> <java-symbol type="attr" name="actionModeShareDrawable" /> <java-symbol type="attr" name="actionModeShareDrawable" /> <java-symbol type="attr" name="alertDialogCenterButtons" /> <java-symbol type="attr" name="alertDialogCenterButtons" /> Loading Loading @@ -334,9 +339,11 @@ <java-symbol type="string" name="addToDictionary" /> <java-symbol type="string" name="addToDictionary" /> <java-symbol type="string" name="action_bar_home_description" /> <java-symbol type="string" name="action_bar_home_description" /> <java-symbol type="string" name="action_bar_up_description" /> <java-symbol type="string" name="action_bar_up_description" /> <java-symbol type="string" name="allow" /> <java-symbol type="string" name="app_running_notification_title" /> <java-symbol type="string" name="app_running_notification_title" /> <java-symbol type="string" name="app_running_notification_text" /> <java-symbol type="string" name="app_running_notification_text" /> <java-symbol type="string" name="delete" /> <java-symbol type="string" name="delete" /> <java-symbol type="string" name="deny" /> <java-symbol type="string" name="deleteText" /> <java-symbol type="string" name="deleteText" /> <java-symbol type="string" name="ellipsis_two_dots" /> <java-symbol type="string" name="ellipsis_two_dots" /> <java-symbol type="string" name="ellipsis" /> <java-symbol type="string" name="ellipsis" /> Loading @@ -346,6 +353,7 @@ <java-symbol type="string" name="menu_enter_shortcut_label" /> <java-symbol type="string" name="menu_enter_shortcut_label" /> <java-symbol type="string" name="menu_space_shortcut_label" /> <java-symbol type="string" name="menu_space_shortcut_label" /> <java-symbol type="string" name="notification_title" /> <java-symbol type="string" name="notification_title" /> <java-symbol type="string" name="permission_request_notification_title" /> <java-symbol type="string" name="permission_request_notification_with_subtitle" /> <java-symbol type="string" name="permission_request_notification_with_subtitle" /> <java-symbol type="string" name="prepend_shortcut_label" /> <java-symbol type="string" name="prepend_shortcut_label" /> <java-symbol type="string" name="replace" /> <java-symbol type="string" name="replace" /> Loading Loading @@ -1122,6 +1130,7 @@ <java-symbol type="layout" name="locale_picker_item" /> <java-symbol type="layout" name="locale_picker_item" /> <java-symbol type="layout" name="media_controller" /> <java-symbol type="layout" name="media_controller" /> <java-symbol type="layout" name="overlay_display_window" /> <java-symbol type="layout" name="overlay_display_window" /> <java-symbol type="layout" name="permission_confirmation_dialog" /> <java-symbol type="layout" name="preference" /> <java-symbol type="layout" name="preference" /> <java-symbol type="layout" name="preference_header_item" /> <java-symbol type="layout" name="preference_header_item" /> <java-symbol type="layout" name="preference_list_content" /> <java-symbol type="layout" name="preference_list_content" /> Loading Loading @@ -1556,6 +1565,7 @@ <java-symbol type="anim" name="rotation_animation_enter" /> <java-symbol type="anim" name="rotation_animation_enter" /> <java-symbol type="anim" name="shrink_fade_out_center" /> <java-symbol type="anim" name="shrink_fade_out_center" /> <java-symbol type="anim" name="grow_fade_in_center" /> <java-symbol type="anim" name="grow_fade_in_center" /> <java-symbol type="array" name="app_ops_labels" /> <java-symbol type="array" name="config_autoBrightnessButtonBacklightValues" /> <java-symbol type="array" name="config_autoBrightnessButtonBacklightValues" /> <java-symbol type="array" name="config_autoBrightnessKeyboardBacklightValues" /> <java-symbol type="array" name="config_autoBrightnessKeyboardBacklightValues" /> <java-symbol type="array" name="config_autoBrightnessLcdBacklightValues" /> <java-symbol type="array" name="config_autoBrightnessLcdBacklightValues" /> Loading services/java/com/android/server/AppOpsService.java +226 −45 Original line number Original line Diff line number Diff line /* /* * Copyright (c) 2013, The Linux Foundation. All rights reserved. * Not a Contribution. * * Copyright (C) 2012 The Android Open Source Project * Copyright (C) 2012 The Android Open Source Project * * * Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License"); Loading Loading @@ -30,16 +33,21 @@ import java.util.List; import java.util.Map; import java.util.Map; import android.app.AppOpsManager; import android.app.AppOpsManager; import android.app.Dialog; import android.content.Context; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException; import android.os.AsyncTask; import android.os.AsyncTask; import android.os.Binder; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.Handler; import android.os.IBinder; import android.os.IBinder; import android.os.Message; import android.os.Process; import android.os.Process; import android.os.RemoteException; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserHandle; import android.util.AtomicFile; import android.util.AtomicFile; import android.util.Log; import android.util.Log; Loading @@ -58,9 +66,12 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import org.xmlpull.v1.XmlSerializer; import com.android.server.PermissionDialogResult.Result; public class AppOpsService extends IAppOpsService.Stub { public class AppOpsService extends IAppOpsService.Stub { static final String TAG = "AppOps"; static final String TAG = "AppOps"; static final boolean DEBUG = false; static final boolean DEBUG = false; static final String STRICT_PERMISSION_PROPERTY = "persist.sys.strict_op_enable"; // Write at most every 30 minutes. // Write at most every 30 minutes. static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000; static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000; Loading @@ -68,6 +79,9 @@ public class AppOpsService extends IAppOpsService.Stub { Context mContext; Context mContext; final AtomicFile mFile; final AtomicFile mFile; final Handler mHandler; final Handler mHandler; final boolean mStrictEnable; static final int SHOW_PERMISSION_DIALOG = 1; private static final int[] PRIVACY_GUARD_OP_STATES = new int[] { private static final int[] PRIVACY_GUARD_OP_STATES = new int[] { AppOpsManager.OP_COARSE_LOCATION, AppOpsManager.OP_COARSE_LOCATION, Loading Loading @@ -109,14 +123,23 @@ public class AppOpsService extends IAppOpsService.Stub { public final static class Op { public final static class Op { public final int op; public final int op; public int mode; public int mode; public final int defaultMode; public int duration; public int duration; public long time; public long time; public long rejectTime; public long rejectTime; public int nesting; public int nesting; public int tempNesting; public PermissionDialogResult dialogResult; public Op(int _op) { public Op(int _op, boolean strict) { op = _op; op = _op; if (!strict) { mode = AppOpsManager.MODE_ALLOWED; mode = AppOpsManager.MODE_ALLOWED; } else { mode = AppOpsManager.MODE_ASK; } dialogResult = new PermissionDialogResult(); defaultMode = mode; } } } } Loading Loading @@ -149,8 +172,31 @@ public class AppOpsService extends IAppOpsService.Stub { } } public AppOpsService(File storagePath) { public AppOpsService(File storagePath) { mStrictEnable = "true".equals(SystemProperties.get(STRICT_PERMISSION_PROPERTY)); mFile = new AtomicFile(storagePath); mFile = new AtomicFile(storagePath); mHandler = new Handler(); mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case SHOW_PERMISSION_DIALOG: { Bundle data = msg.getData(); synchronized (this) { Op op = (Op) msg.obj; Result res = (Result) data.getParcelable("result"); op.dialogResult.register(res); if (op.dialogResult.mDialog == null) { Integer code = data.getInt("code"); Integer uid = data.getInt("uid"); String packageName = data.getString("packageName"); PermissionDialog d = new PermissionDialog(mContext, AppOpsService.this, code, uid, packageName); op.dialogResult.mDialog = d; d.show(); } } }break; } } }; readState(); readState(); } } Loading Loading @@ -341,11 +387,13 @@ public class AppOpsService extends IAppOpsService.Stub { } } repCbs.addAll(cbs); repCbs.addAll(cbs); } } if (mode == AppOpsManager.MODE_ALLOWED) { if (mode == op.defaultMode) { // If going into the default mode, prune this op // If going into the default mode, prune this op // if there is nothing else interesting in it. // if there is nothing else interesting in it. pruneOp(op, uid, packageName); pruneOp(op, uid, packageName); } } scheduleWriteNowLocked(); scheduleWriteNowLocked(); } } } } Loading Loading @@ -395,8 +443,8 @@ public class AppOpsService extends IAppOpsService.Stub { Ops pkgOps = ent.getValue(); Ops pkgOps = ent.getValue(); for (int j=0; j<pkgOps.size(); j++) { for (int j=0; j<pkgOps.size(); j++) { Op curOp = pkgOps.valueAt(j); Op curOp = pkgOps.valueAt(j); if (curOp.mode != AppOpsManager.MODE_ALLOWED) { if (curOp.mode != curOp.defaultMode) { curOp.mode = AppOpsManager.MODE_ALLOWED; curOp.mode = curOp.defaultMode; changed = true; changed = true; callbacks = addCallbacks(callbacks, packageName, curOp.op, callbacks = addCallbacks(callbacks, packageName, curOp.op, mOpModeWatchers.get(curOp.op)); mOpModeWatchers.get(curOp.op)); Loading Loading @@ -481,14 +529,130 @@ public class AppOpsService extends IAppOpsService.Stub { } } } } private boolean isStrict(int code, int uid, String packageName) { if (!mStrictEnable) { return false; } return ((uid > Process.FIRST_APPLICATION_UID) && (AppOpsManager.opStrict(code))); } private void recordOperationLocked(int code, int uid, String packageName, int mode) { int switchCode = AppOpsManager.opToSwitch(code); Op op = getOpLocked(switchCode, uid, packageName, false); if (op != null) { if (mode == AppOpsManager.MODE_IGNORED) { if (DEBUG) Log.d(TAG, "recordOperation: reject #" + mode + " for code " + switchCode + " (" + code + ") uid " + uid + " package " + packageName); op.rejectTime = System.currentTimeMillis(); } else if (mode == AppOpsManager.MODE_ALLOWED) { if (DEBUG) Log.d(TAG, "recordOperation: allowing code " + code + " uid " + uid + " package " + packageName); op.time = System.currentTimeMillis(); op.rejectTime = 0; } } } public void notifyOperation(int code, int uid, String packageName, int mode, boolean remember) { verifyIncomingUid(uid); verifyIncomingOp(code); ArrayList<Callback> repCbs = null; code = AppOpsManager.opToSwitch(code); synchronized (this) { Op op = getOpLocked(code, uid, packageName, true); if (op != null) { // Record this mode recordOperationLocked(code, uid, packageName, mode); // Increase nesting for all pending startOperation requests if(mode == AppOpsManager.MODE_ALLOWED) { if (op.nesting == 0) { op.time = System.currentTimeMillis(); op.rejectTime = 0; op.duration = -1; } op.nesting = op.nesting + op.tempNesting; } // Reset tempNesting op.tempNesting = 0; // Send result to all waiting client op.dialogResult.notifyAll(mode); op.dialogResult.mDialog = null; // if User selected to remember her choice if (remember) { 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); } if (mode == op.defaultMode) { // If going into the default mode, prune this op // if there is nothing else interesting in it. pruneOp(op, uid, packageName); } scheduleWriteNowLocked(); } } } } if (repCbs != null) { for (int i=0; i<repCbs.size(); i++) { try { repCbs.get(i).mCallback.opChanged(code, packageName); } catch (RemoteException e) { } } } } private Result askOperationLocked(int code, int uid, String packageName, Op op) { Result result = new Result(); final long origId = Binder.clearCallingIdentity(); Message msg = Message.obtain(); msg.what = SHOW_PERMISSION_DIALOG; Bundle data = new Bundle(); data.putParcelable("result", result); data.putInt("code", code); data.putString("packageName", packageName); data.putInt("uid", uid); msg.setData(data); msg.obj = op; mHandler.sendMessage(msg); Binder.restoreCallingIdentity(origId); return result; } @Override @Override public int checkOperation(int code, int uid, String packageName) { public int checkOperation(int code, int uid, String packageName) { boolean strict; verifyIncomingUid(uid); verifyIncomingUid(uid); verifyIncomingOp(code); verifyIncomingOp(code); synchronized (this) { synchronized (this) { Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false); Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false); if (op == null) { if (op == null) { if (!isStrict(code, uid, packageName)) { return AppOpsManager.MODE_ALLOWED; return AppOpsManager.MODE_ALLOWED; } else { return AppOpsManager.MODE_ASK; } } } return op.mode; return op.mode; } } Loading @@ -496,67 +660,83 @@ public class AppOpsService extends IAppOpsService.Stub { @Override @Override public int noteOperation(int code, int uid, String packageName) { public int noteOperation(int code, int uid, String packageName) { int mode; Ops ops; Op op; final Op switchOp; final int switchCode; final Result res; verifyIncomingUid(uid); verifyIncomingUid(uid); verifyIncomingOp(code); verifyIncomingOp(code); synchronized (this) { synchronized (this) { Ops ops = getOpsLocked(uid, packageName, true); ops = getOpsLocked(uid, packageName, true); if (ops == null) { if (ops == null) { if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid + " package " + packageName); + " package " + packageName); return AppOpsManager.MODE_IGNORED; return AppOpsManager.MODE_IGNORED; } } Op op = getOpLocked(ops, code, true); boolean strict = isStrict(code, uid, packageName); op = getOpLocked(ops, uid, code, true, strict); if (op.duration == -1) { if (op.duration == -1) { Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code " + code + " time=" + op.time + " duration=" + op.duration); + " code " + code + " time=" + op.time + " duration=" + op.duration); } } op.duration = 0; op.duration = 0; final int switchCode = AppOpsManager.opToSwitch(code); switchCode = AppOpsManager.opToSwitch(code); final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op; switchOp = switchCode != code ? getOpLocked(ops, uid, switchCode, true, strict) : op; if (switchOp.mode != AppOpsManager.MODE_ALLOWED) { mode = switchOp.mode; if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code " if (mode != AppOpsManager.MODE_ASK) { + switchCode + " (" + code + ") uid " + uid + " package " + packageName); recordOperationLocked(code, uid, packageName, switchOp.mode); op.rejectTime = System.currentTimeMillis(); return switchOp.mode; return switchOp.mode; } else { res = askOperationLocked(code, uid, packageName, switchOp); } } if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid + " package " + packageName); op.time = System.currentTimeMillis(); op.rejectTime = 0; return AppOpsManager.MODE_ALLOWED; } } return res.get(); } } @Override @Override public int startOperation(int code, int uid, String packageName) { public int startOperation(int code, int uid, String packageName) { int mode; Ops ops; Op op; final Op switchOp; final int switchCode; final Result res; verifyIncomingUid(uid); verifyIncomingUid(uid); verifyIncomingOp(code); verifyIncomingOp(code); synchronized (this) { synchronized (this) { Ops ops = getOpsLocked(uid, packageName, true); ops = getOpsLocked(uid, packageName, true); if (ops == null) { if (ops == null) { if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid + " package " + packageName); + " package " + packageName); return AppOpsManager.MODE_IGNORED; return AppOpsManager.MODE_IGNORED; } } Op op = getOpLocked(ops, code, true); boolean strict = isStrict(code, uid, packageName); final int switchCode = AppOpsManager.opToSwitch(code); op = getOpLocked(ops, uid, code, true, strict); final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op; switchCode = AppOpsManager.opToSwitch(code); if (switchOp.mode != AppOpsManager.MODE_ALLOWED) { switchOp = switchCode != code ? getOpLocked(ops, uid, switchCode, true, strict) : op; if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code " mode = switchOp.mode; + switchCode + " (" + code + ") uid " + uid + " package " + packageName); if (mode != AppOpsManager.MODE_ASK) { op.rejectTime = System.currentTimeMillis(); recordOperationLocked(code, uid, packageName, switchOp.mode); return switchOp.mode; if (mode == AppOpsManager.MODE_ALLOWED) { } if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid + " package " + packageName); if (op.nesting == 0) { if (op.nesting == 0) { op.time = System.currentTimeMillis(); op.time = System.currentTimeMillis(); op.rejectTime = 0; op.rejectTime = 0; op.duration = -1; op.duration = -1; } } op.nesting++; op.nesting++; return AppOpsManager.MODE_ALLOWED; } } return switchOp.mode; } else { op.tempNesting++; res = askOperationLocked(code, uid, packageName, switchOp); } } return res.get(); } } @Override @Override Loading Loading @@ -669,16 +849,17 @@ public class AppOpsService extends IAppOpsService.Stub { if (ops == null) { if (ops == null) { return null; return null; } } return getOpLocked(ops, code, edit); return getOpLocked(ops, uid, code, edit, isStrict(code, uid, packageName)); } } private Op getOpLocked(Ops ops, int code, boolean edit) { private Op getOpLocked(Ops ops, int uid, int code, boolean edit, boolean strict) { Op op = ops.get(code); Op op = ops.get(code); if (op == null) { if (op == null) { if (!edit) { if (!edit) { return null; return null; } } op = new Op(code); op = new Op(code, strict); ops.put(code, op); ops.put(code, op); } } if (edit) { if (edit) { Loading Loading @@ -788,7 +969,9 @@ public class AppOpsService extends IAppOpsService.Stub { String tagName = parser.getName(); String tagName = parser.getName(); if (tagName.equals("op")) { if (tagName.equals("op")) { Op op = new Op(Integer.parseInt(parser.getAttributeValue(null, "n"))); int code = Integer.parseInt(parser.getAttributeValue(null, "n")); boolean strict = isStrict(code, uid, pkgName); Op op = new Op(code, strict); String mode = parser.getAttributeValue(null, "m"); String mode = parser.getAttributeValue(null, "m"); if (mode != null) { if (mode != null) { op.mode = Integer.parseInt(mode); op.mode = Integer.parseInt(mode); Loading Loading @@ -861,9 +1044,7 @@ public class AppOpsService extends IAppOpsService.Stub { AppOpsManager.OpEntry op = ops.get(j); AppOpsManager.OpEntry op = ops.get(j); out.startTag(null, "op"); out.startTag(null, "op"); out.attribute(null, "n", Integer.toString(op.getOp())); out.attribute(null, "n", Integer.toString(op.getOp())); if (op.getMode() != AppOpsManager.MODE_ALLOWED) { out.attribute(null, "m", Integer.toString(op.getMode())); out.attribute(null, "m", Integer.toString(op.getMode())); } long time = op.getTime(); long time = op.getTime(); if (time != 0) { if (time != 0) { out.attribute(null, "t", Long.toString(time)); out.attribute(null, "t", Long.toString(time)); Loading Loading
core/java/android/app/AppOpsManager.java +51 −0 Original line number Original line Diff line number Diff line /* /* * Copyright (c) 2013, The Linux Foundation. All rights reserved. * Not a Contribution. * * Copyright (C) 2012 The Android Open Source Project * Copyright (C) 2012 The Android Open Source Project * * * Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License"); Loading Loading @@ -59,6 +62,7 @@ public class AppOpsManager { public static final int MODE_ALLOWED = 0; public static final int MODE_ALLOWED = 0; public static final int MODE_IGNORED = 1; public static final int MODE_IGNORED = 1; public static final int MODE_ERRORED = 2; public static final int MODE_ERRORED = 2; public static final int MODE_ASK = 3; // when adding one of these: // when adding one of these: // - increment _NUM_OP // - increment _NUM_OP Loading Loading @@ -99,6 +103,46 @@ public class AppOpsManager { /** @hide */ /** @hide */ public static final int _NUM_OP = 31; public static final int _NUM_OP = 31; /** * Map to check if each operation is strict or not, to determine default * value of each operation. * If strict then AppOpsService should assign MODE_ASK value to operation * by default. */ private static boolean[] sOpStrict = new boolean[] { true, //OP_COARSE_LOCATION true, //OP_FINE_LOCATION true, //OP_GPS false, //OP_VIBRATE true, //OP_READ_CONTACTS true, //OP_WRITE_CONTACTS true, //OP_READ_CALL_LOG true, //OP_WRITE_CALL_LOG false, //OP_READ_CALENDAR false, //OP_WRITE_CALENDAR true, //OP_WIFI_SCAN false, //OP_POST_NOTIFICATION false, //OP_NEIGHBORING_CELLS true, //OP_CALL_PHONE true, //OP_READ_SMS true, //OP_WRITE_SMS true, //OP_RECEIVE_SMS false, //OP_RECEIVE_EMERGECY_SMS true, //OP_RECEIVE_MMS false, //OP_RECEIVE_WAP_PUSH true, //OP_SEND_SMS true, //OP_READ_ICC_SMS true, //OP_WRITE_ICC_SMS false, //OP_WRITE_SETTINGS false, //OP_SYSTEM_ALERT_WINDOW false, //OP_ACCESS_NOTIFICATIONS true, //OP_CAMERA true, //OP_RECORD_AUDIO true, //OP_PLAY_AUDIO false, //OP_READ_CLIPBOARD false, //OP_WRITE_CLIPBOARD }; /** /** * This maps each operation to the operation that serves as the * This maps each operation to the operation that serves as the * switch to determine whether it is allowed. Generally this is * switch to determine whether it is allowed. Generally this is Loading Loading @@ -217,6 +261,13 @@ public class AppOpsManager { null, // no permission for writing clipboard null, // no permission for writing clipboard }; }; /** * Check if given operation is strict or not. */ public static boolean opStrict(int op) { return sOpStrict[op]; } /** /** * Retrieve the op switch that controls the given operation. * Retrieve the op switch that controls the given operation. */ */ Loading
core/res/res/layout/permission_confirmation_dialog.xml 0 → 100644 +46 −0 Original line number Original line Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- /* ** Copyright (c) 2013, The Linux Foundation. All rights reserved. ** Not a Contribution. ** ** Copyright 2012 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. */ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/parentPanel" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="8dip" android:layout_marginRight="8dip" android:orientation="vertical"> <TextView android:id="@+id/permission_text" style="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="20dip" android:paddingRight="20dip" android:paddingTop="16dip" android:paddingBottom="16dip" /> <CheckBox android:id="@+id/permission_remember_choice_checkbox" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/save_password_remember" /> </LinearLayout>
core/res/res/values/cm_arrays.xml +34 −0 Original line number Original line Diff line number Diff line Loading @@ -52,4 +52,38 @@ <item>2</item> <item>2</item> </string-array> </string-array> <!-- User display names for app ops codes --> <string-array name="app_ops_labels"> <item>Trying to access location</item> <item>Trying to access location</item> <item>Trying to access location</item> <item>Trying to use vibrate</item> <item>Trying to read contacts</item> <item>Trying to modify contacts</item> <item>Trying to read call log</item> <item>Trying to modify call log</item> <item>Trying to read calendar</item> <item>Trying to modify calendar</item> <item>Trying to access location</item> <item>Trying to post notification</item> <item>Trying to access location</item> <item>Trying to make phone call</item> <item>Trying to read SMS/MMS</item> <item>Trying to write/modify SMS/MMS</item> <item>Trying to receive SMS/MMS</item> <item>Trying to receive SMS/MMS</item> <item>Trying to receive SMS/MMS</item> <item>Trying to receive SMS/MMS</item> <item>Trying to send SMS/MMS</item> <item>Trying to read SMS/MMS</item> <item>Trying to write/modify SMS/MMS</item> <item>Trying to modify settings</item> <item>Trying to draw on top</item> <item>Trying to access notifications</item> <item>Trying to access Camera</item> <item>Trying to record audio</item> <item>Trying to play audio</item> <item>Trying to read clipboard</item> <item>Trying to modify clipboard</item> </string-array> </resources> </resources>
core/res/res/values/symbols.xml +11 −1 Original line number Original line Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?> <!-- <!-- /* Copyright 2012, The Android Open Source Project /* Copyright (c) 2013, The Linux Foundation. All rights reserved. ** Not a Contribution. ** ** Copyright 2012, The Android Open Source Project ** ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** you may not use this file except in compliance with the License. Loading Loading @@ -218,6 +221,8 @@ <java-symbol type="id" name="sms_short_code_remember_undo_instruction" /> <java-symbol type="id" name="sms_short_code_remember_undo_instruction" /> <java-symbol type="id" name="breadcrumb_section" /> <java-symbol type="id" name="breadcrumb_section" /> <java-symbol type="id" name="action_bar_spinner" /> <java-symbol type="id" name="action_bar_spinner" /> <java-symbol type="id" name="permission_text" /> <java-symbol type="id" name="permission_remember_choice_checkbox" /> <java-symbol type="attr" name="actionModeShareDrawable" /> <java-symbol type="attr" name="actionModeShareDrawable" /> <java-symbol type="attr" name="alertDialogCenterButtons" /> <java-symbol type="attr" name="alertDialogCenterButtons" /> Loading Loading @@ -334,9 +339,11 @@ <java-symbol type="string" name="addToDictionary" /> <java-symbol type="string" name="addToDictionary" /> <java-symbol type="string" name="action_bar_home_description" /> <java-symbol type="string" name="action_bar_home_description" /> <java-symbol type="string" name="action_bar_up_description" /> <java-symbol type="string" name="action_bar_up_description" /> <java-symbol type="string" name="allow" /> <java-symbol type="string" name="app_running_notification_title" /> <java-symbol type="string" name="app_running_notification_title" /> <java-symbol type="string" name="app_running_notification_text" /> <java-symbol type="string" name="app_running_notification_text" /> <java-symbol type="string" name="delete" /> <java-symbol type="string" name="delete" /> <java-symbol type="string" name="deny" /> <java-symbol type="string" name="deleteText" /> <java-symbol type="string" name="deleteText" /> <java-symbol type="string" name="ellipsis_two_dots" /> <java-symbol type="string" name="ellipsis_two_dots" /> <java-symbol type="string" name="ellipsis" /> <java-symbol type="string" name="ellipsis" /> Loading @@ -346,6 +353,7 @@ <java-symbol type="string" name="menu_enter_shortcut_label" /> <java-symbol type="string" name="menu_enter_shortcut_label" /> <java-symbol type="string" name="menu_space_shortcut_label" /> <java-symbol type="string" name="menu_space_shortcut_label" /> <java-symbol type="string" name="notification_title" /> <java-symbol type="string" name="notification_title" /> <java-symbol type="string" name="permission_request_notification_title" /> <java-symbol type="string" name="permission_request_notification_with_subtitle" /> <java-symbol type="string" name="permission_request_notification_with_subtitle" /> <java-symbol type="string" name="prepend_shortcut_label" /> <java-symbol type="string" name="prepend_shortcut_label" /> <java-symbol type="string" name="replace" /> <java-symbol type="string" name="replace" /> Loading Loading @@ -1122,6 +1130,7 @@ <java-symbol type="layout" name="locale_picker_item" /> <java-symbol type="layout" name="locale_picker_item" /> <java-symbol type="layout" name="media_controller" /> <java-symbol type="layout" name="media_controller" /> <java-symbol type="layout" name="overlay_display_window" /> <java-symbol type="layout" name="overlay_display_window" /> <java-symbol type="layout" name="permission_confirmation_dialog" /> <java-symbol type="layout" name="preference" /> <java-symbol type="layout" name="preference" /> <java-symbol type="layout" name="preference_header_item" /> <java-symbol type="layout" name="preference_header_item" /> <java-symbol type="layout" name="preference_list_content" /> <java-symbol type="layout" name="preference_list_content" /> Loading Loading @@ -1556,6 +1565,7 @@ <java-symbol type="anim" name="rotation_animation_enter" /> <java-symbol type="anim" name="rotation_animation_enter" /> <java-symbol type="anim" name="shrink_fade_out_center" /> <java-symbol type="anim" name="shrink_fade_out_center" /> <java-symbol type="anim" name="grow_fade_in_center" /> <java-symbol type="anim" name="grow_fade_in_center" /> <java-symbol type="array" name="app_ops_labels" /> <java-symbol type="array" name="config_autoBrightnessButtonBacklightValues" /> <java-symbol type="array" name="config_autoBrightnessButtonBacklightValues" /> <java-symbol type="array" name="config_autoBrightnessKeyboardBacklightValues" /> <java-symbol type="array" name="config_autoBrightnessKeyboardBacklightValues" /> <java-symbol type="array" name="config_autoBrightnessLcdBacklightValues" /> <java-symbol type="array" name="config_autoBrightnessLcdBacklightValues" /> Loading
services/java/com/android/server/AppOpsService.java +226 −45 Original line number Original line Diff line number Diff line /* /* * Copyright (c) 2013, The Linux Foundation. All rights reserved. * Not a Contribution. * * Copyright (C) 2012 The Android Open Source Project * Copyright (C) 2012 The Android Open Source Project * * * Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License"); Loading Loading @@ -30,16 +33,21 @@ import java.util.List; import java.util.Map; import java.util.Map; import android.app.AppOpsManager; import android.app.AppOpsManager; import android.app.Dialog; import android.content.Context; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException; import android.os.AsyncTask; import android.os.AsyncTask; import android.os.Binder; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.Handler; import android.os.IBinder; import android.os.IBinder; import android.os.Message; import android.os.Process; import android.os.Process; import android.os.RemoteException; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserHandle; import android.util.AtomicFile; import android.util.AtomicFile; import android.util.Log; import android.util.Log; Loading @@ -58,9 +66,12 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import org.xmlpull.v1.XmlSerializer; import com.android.server.PermissionDialogResult.Result; public class AppOpsService extends IAppOpsService.Stub { public class AppOpsService extends IAppOpsService.Stub { static final String TAG = "AppOps"; static final String TAG = "AppOps"; static final boolean DEBUG = false; static final boolean DEBUG = false; static final String STRICT_PERMISSION_PROPERTY = "persist.sys.strict_op_enable"; // Write at most every 30 minutes. // Write at most every 30 minutes. static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000; static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000; Loading @@ -68,6 +79,9 @@ public class AppOpsService extends IAppOpsService.Stub { Context mContext; Context mContext; final AtomicFile mFile; final AtomicFile mFile; final Handler mHandler; final Handler mHandler; final boolean mStrictEnable; static final int SHOW_PERMISSION_DIALOG = 1; private static final int[] PRIVACY_GUARD_OP_STATES = new int[] { private static final int[] PRIVACY_GUARD_OP_STATES = new int[] { AppOpsManager.OP_COARSE_LOCATION, AppOpsManager.OP_COARSE_LOCATION, Loading Loading @@ -109,14 +123,23 @@ public class AppOpsService extends IAppOpsService.Stub { public final static class Op { public final static class Op { public final int op; public final int op; public int mode; public int mode; public final int defaultMode; public int duration; public int duration; public long time; public long time; public long rejectTime; public long rejectTime; public int nesting; public int nesting; public int tempNesting; public PermissionDialogResult dialogResult; public Op(int _op) { public Op(int _op, boolean strict) { op = _op; op = _op; if (!strict) { mode = AppOpsManager.MODE_ALLOWED; mode = AppOpsManager.MODE_ALLOWED; } else { mode = AppOpsManager.MODE_ASK; } dialogResult = new PermissionDialogResult(); defaultMode = mode; } } } } Loading Loading @@ -149,8 +172,31 @@ public class AppOpsService extends IAppOpsService.Stub { } } public AppOpsService(File storagePath) { public AppOpsService(File storagePath) { mStrictEnable = "true".equals(SystemProperties.get(STRICT_PERMISSION_PROPERTY)); mFile = new AtomicFile(storagePath); mFile = new AtomicFile(storagePath); mHandler = new Handler(); mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case SHOW_PERMISSION_DIALOG: { Bundle data = msg.getData(); synchronized (this) { Op op = (Op) msg.obj; Result res = (Result) data.getParcelable("result"); op.dialogResult.register(res); if (op.dialogResult.mDialog == null) { Integer code = data.getInt("code"); Integer uid = data.getInt("uid"); String packageName = data.getString("packageName"); PermissionDialog d = new PermissionDialog(mContext, AppOpsService.this, code, uid, packageName); op.dialogResult.mDialog = d; d.show(); } } }break; } } }; readState(); readState(); } } Loading Loading @@ -341,11 +387,13 @@ public class AppOpsService extends IAppOpsService.Stub { } } repCbs.addAll(cbs); repCbs.addAll(cbs); } } if (mode == AppOpsManager.MODE_ALLOWED) { if (mode == op.defaultMode) { // If going into the default mode, prune this op // If going into the default mode, prune this op // if there is nothing else interesting in it. // if there is nothing else interesting in it. pruneOp(op, uid, packageName); pruneOp(op, uid, packageName); } } scheduleWriteNowLocked(); scheduleWriteNowLocked(); } } } } Loading Loading @@ -395,8 +443,8 @@ public class AppOpsService extends IAppOpsService.Stub { Ops pkgOps = ent.getValue(); Ops pkgOps = ent.getValue(); for (int j=0; j<pkgOps.size(); j++) { for (int j=0; j<pkgOps.size(); j++) { Op curOp = pkgOps.valueAt(j); Op curOp = pkgOps.valueAt(j); if (curOp.mode != AppOpsManager.MODE_ALLOWED) { if (curOp.mode != curOp.defaultMode) { curOp.mode = AppOpsManager.MODE_ALLOWED; curOp.mode = curOp.defaultMode; changed = true; changed = true; callbacks = addCallbacks(callbacks, packageName, curOp.op, callbacks = addCallbacks(callbacks, packageName, curOp.op, mOpModeWatchers.get(curOp.op)); mOpModeWatchers.get(curOp.op)); Loading Loading @@ -481,14 +529,130 @@ public class AppOpsService extends IAppOpsService.Stub { } } } } private boolean isStrict(int code, int uid, String packageName) { if (!mStrictEnable) { return false; } return ((uid > Process.FIRST_APPLICATION_UID) && (AppOpsManager.opStrict(code))); } private void recordOperationLocked(int code, int uid, String packageName, int mode) { int switchCode = AppOpsManager.opToSwitch(code); Op op = getOpLocked(switchCode, uid, packageName, false); if (op != null) { if (mode == AppOpsManager.MODE_IGNORED) { if (DEBUG) Log.d(TAG, "recordOperation: reject #" + mode + " for code " + switchCode + " (" + code + ") uid " + uid + " package " + packageName); op.rejectTime = System.currentTimeMillis(); } else if (mode == AppOpsManager.MODE_ALLOWED) { if (DEBUG) Log.d(TAG, "recordOperation: allowing code " + code + " uid " + uid + " package " + packageName); op.time = System.currentTimeMillis(); op.rejectTime = 0; } } } public void notifyOperation(int code, int uid, String packageName, int mode, boolean remember) { verifyIncomingUid(uid); verifyIncomingOp(code); ArrayList<Callback> repCbs = null; code = AppOpsManager.opToSwitch(code); synchronized (this) { Op op = getOpLocked(code, uid, packageName, true); if (op != null) { // Record this mode recordOperationLocked(code, uid, packageName, mode); // Increase nesting for all pending startOperation requests if(mode == AppOpsManager.MODE_ALLOWED) { if (op.nesting == 0) { op.time = System.currentTimeMillis(); op.rejectTime = 0; op.duration = -1; } op.nesting = op.nesting + op.tempNesting; } // Reset tempNesting op.tempNesting = 0; // Send result to all waiting client op.dialogResult.notifyAll(mode); op.dialogResult.mDialog = null; // if User selected to remember her choice if (remember) { 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); } if (mode == op.defaultMode) { // If going into the default mode, prune this op // if there is nothing else interesting in it. pruneOp(op, uid, packageName); } scheduleWriteNowLocked(); } } } } if (repCbs != null) { for (int i=0; i<repCbs.size(); i++) { try { repCbs.get(i).mCallback.opChanged(code, packageName); } catch (RemoteException e) { } } } } private Result askOperationLocked(int code, int uid, String packageName, Op op) { Result result = new Result(); final long origId = Binder.clearCallingIdentity(); Message msg = Message.obtain(); msg.what = SHOW_PERMISSION_DIALOG; Bundle data = new Bundle(); data.putParcelable("result", result); data.putInt("code", code); data.putString("packageName", packageName); data.putInt("uid", uid); msg.setData(data); msg.obj = op; mHandler.sendMessage(msg); Binder.restoreCallingIdentity(origId); return result; } @Override @Override public int checkOperation(int code, int uid, String packageName) { public int checkOperation(int code, int uid, String packageName) { boolean strict; verifyIncomingUid(uid); verifyIncomingUid(uid); verifyIncomingOp(code); verifyIncomingOp(code); synchronized (this) { synchronized (this) { Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false); Op op = getOpLocked(AppOpsManager.opToSwitch(code), uid, packageName, false); if (op == null) { if (op == null) { if (!isStrict(code, uid, packageName)) { return AppOpsManager.MODE_ALLOWED; return AppOpsManager.MODE_ALLOWED; } else { return AppOpsManager.MODE_ASK; } } } return op.mode; return op.mode; } } Loading @@ -496,67 +660,83 @@ public class AppOpsService extends IAppOpsService.Stub { @Override @Override public int noteOperation(int code, int uid, String packageName) { public int noteOperation(int code, int uid, String packageName) { int mode; Ops ops; Op op; final Op switchOp; final int switchCode; final Result res; verifyIncomingUid(uid); verifyIncomingUid(uid); verifyIncomingOp(code); verifyIncomingOp(code); synchronized (this) { synchronized (this) { Ops ops = getOpsLocked(uid, packageName, true); ops = getOpsLocked(uid, packageName, true); if (ops == null) { if (ops == null) { if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid + " package " + packageName); + " package " + packageName); return AppOpsManager.MODE_IGNORED; return AppOpsManager.MODE_IGNORED; } } Op op = getOpLocked(ops, code, true); boolean strict = isStrict(code, uid, packageName); op = getOpLocked(ops, uid, code, true, strict); if (op.duration == -1) { if (op.duration == -1) { Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code " + code + " time=" + op.time + " duration=" + op.duration); + " code " + code + " time=" + op.time + " duration=" + op.duration); } } op.duration = 0; op.duration = 0; final int switchCode = AppOpsManager.opToSwitch(code); switchCode = AppOpsManager.opToSwitch(code); final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op; switchOp = switchCode != code ? getOpLocked(ops, uid, switchCode, true, strict) : op; if (switchOp.mode != AppOpsManager.MODE_ALLOWED) { mode = switchOp.mode; if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code " if (mode != AppOpsManager.MODE_ASK) { + switchCode + " (" + code + ") uid " + uid + " package " + packageName); recordOperationLocked(code, uid, packageName, switchOp.mode); op.rejectTime = System.currentTimeMillis(); return switchOp.mode; return switchOp.mode; } else { res = askOperationLocked(code, uid, packageName, switchOp); } } if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid + " package " + packageName); op.time = System.currentTimeMillis(); op.rejectTime = 0; return AppOpsManager.MODE_ALLOWED; } } return res.get(); } } @Override @Override public int startOperation(int code, int uid, String packageName) { public int startOperation(int code, int uid, String packageName) { int mode; Ops ops; Op op; final Op switchOp; final int switchCode; final Result res; verifyIncomingUid(uid); verifyIncomingUid(uid); verifyIncomingOp(code); verifyIncomingOp(code); synchronized (this) { synchronized (this) { Ops ops = getOpsLocked(uid, packageName, true); ops = getOpsLocked(uid, packageName, true); if (ops == null) { if (ops == null) { if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid + " package " + packageName); + " package " + packageName); return AppOpsManager.MODE_IGNORED; return AppOpsManager.MODE_IGNORED; } } Op op = getOpLocked(ops, code, true); boolean strict = isStrict(code, uid, packageName); final int switchCode = AppOpsManager.opToSwitch(code); op = getOpLocked(ops, uid, code, true, strict); final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op; switchCode = AppOpsManager.opToSwitch(code); if (switchOp.mode != AppOpsManager.MODE_ALLOWED) { switchOp = switchCode != code ? getOpLocked(ops, uid, switchCode, true, strict) : op; if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code " mode = switchOp.mode; + switchCode + " (" + code + ") uid " + uid + " package " + packageName); if (mode != AppOpsManager.MODE_ASK) { op.rejectTime = System.currentTimeMillis(); recordOperationLocked(code, uid, packageName, switchOp.mode); return switchOp.mode; if (mode == AppOpsManager.MODE_ALLOWED) { } if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid + " package " + packageName); if (op.nesting == 0) { if (op.nesting == 0) { op.time = System.currentTimeMillis(); op.time = System.currentTimeMillis(); op.rejectTime = 0; op.rejectTime = 0; op.duration = -1; op.duration = -1; } } op.nesting++; op.nesting++; return AppOpsManager.MODE_ALLOWED; } } return switchOp.mode; } else { op.tempNesting++; res = askOperationLocked(code, uid, packageName, switchOp); } } return res.get(); } } @Override @Override Loading Loading @@ -669,16 +849,17 @@ public class AppOpsService extends IAppOpsService.Stub { if (ops == null) { if (ops == null) { return null; return null; } } return getOpLocked(ops, code, edit); return getOpLocked(ops, uid, code, edit, isStrict(code, uid, packageName)); } } private Op getOpLocked(Ops ops, int code, boolean edit) { private Op getOpLocked(Ops ops, int uid, int code, boolean edit, boolean strict) { Op op = ops.get(code); Op op = ops.get(code); if (op == null) { if (op == null) { if (!edit) { if (!edit) { return null; return null; } } op = new Op(code); op = new Op(code, strict); ops.put(code, op); ops.put(code, op); } } if (edit) { if (edit) { Loading Loading @@ -788,7 +969,9 @@ public class AppOpsService extends IAppOpsService.Stub { String tagName = parser.getName(); String tagName = parser.getName(); if (tagName.equals("op")) { if (tagName.equals("op")) { Op op = new Op(Integer.parseInt(parser.getAttributeValue(null, "n"))); int code = Integer.parseInt(parser.getAttributeValue(null, "n")); boolean strict = isStrict(code, uid, pkgName); Op op = new Op(code, strict); String mode = parser.getAttributeValue(null, "m"); String mode = parser.getAttributeValue(null, "m"); if (mode != null) { if (mode != null) { op.mode = Integer.parseInt(mode); op.mode = Integer.parseInt(mode); Loading Loading @@ -861,9 +1044,7 @@ public class AppOpsService extends IAppOpsService.Stub { AppOpsManager.OpEntry op = ops.get(j); AppOpsManager.OpEntry op = ops.get(j); out.startTag(null, "op"); out.startTag(null, "op"); out.attribute(null, "n", Integer.toString(op.getOp())); out.attribute(null, "n", Integer.toString(op.getOp())); if (op.getMode() != AppOpsManager.MODE_ALLOWED) { out.attribute(null, "m", Integer.toString(op.getMode())); out.attribute(null, "m", Integer.toString(op.getMode())); } long time = op.getTime(); long time = op.getTime(); if (time != 0) { if (time != 0) { out.attribute(null, "t", Long.toString(time)); out.attribute(null, "t", Long.toString(time)); Loading