Home | History | Annotate | Download | only in app
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.app;
     18 
     19 import android.Manifest;
     20 import com.android.internal.app.IAppOpsService;
     21 import com.android.internal.app.IAppOpsCallback;
     22 
     23 import java.util.ArrayList;
     24 import java.util.HashMap;
     25 import java.util.List;
     26 
     27 import android.content.Context;
     28 import android.os.Parcel;
     29 import android.os.Parcelable;
     30 import android.os.Process;
     31 import android.os.RemoteException;
     32 
     33 /**
     34  * API for interacting with "application operation" tracking.  Allows you to:
     35  *
     36  * - Note when operations are happening, and find out if they are allowed for the current caller.
     37  * - Disallow specific apps from doing specific operations.
     38  * - Collect all of the current information about operations that have been executed or are not
     39  * being allowed.
     40  * - Monitor for changes in whether an operation is allowed.
     41  *
     42  * Each operation is identified by a single integer; these integers are a fixed set of
     43  * operations, enumerated by the OP_* constants.
     44  *
     45  * When checking operations, the result is a "mode" integer indicating the current setting
     46  * for the operation under that caller: MODE_ALLOWED, MODE_IGNORED (don't execute the operation but
     47  * fake its behavior enough so that the caller doesn't crash), MODE_ERRORED (through a
     48  * SecurityException back to the caller; the normal operation calls will do this for you).
     49  *
     50  * @hide
     51  */
     52 public class AppOpsManager {
     53     final Context mContext;
     54     final IAppOpsService mService;
     55     final HashMap<Callback, IAppOpsCallback> mModeWatchers
     56             = new HashMap<Callback, IAppOpsCallback>();
     57 
     58     public static final int MODE_ALLOWED = 0;
     59     public static final int MODE_IGNORED = 1;
     60     public static final int MODE_ERRORED = 2;
     61 
     62     // when adding one of these:
     63     //  - increment _NUM_OP
     64     //  - add rows to sOpToSwitch, sOpNames, sOpPerms
     65     //  - add descriptive strings to Settings/res/values/arrays.xml
     66     public static final int OP_NONE = -1;
     67     public static final int OP_COARSE_LOCATION = 0;
     68     public static final int OP_FINE_LOCATION = 1;
     69     public static final int OP_GPS = 2;
     70     public static final int OP_VIBRATE = 3;
     71     public static final int OP_READ_CONTACTS = 4;
     72     public static final int OP_WRITE_CONTACTS = 5;
     73     public static final int OP_READ_CALL_LOG = 6;
     74     public static final int OP_WRITE_CALL_LOG = 7;
     75     public static final int OP_READ_CALENDAR = 8;
     76     public static final int OP_WRITE_CALENDAR = 9;
     77     public static final int OP_WIFI_SCAN = 10;
     78     public static final int OP_POST_NOTIFICATION = 11;
     79     public static final int OP_NEIGHBORING_CELLS = 12;
     80     public static final int OP_CALL_PHONE = 13;
     81     public static final int OP_READ_SMS = 14;
     82     public static final int OP_WRITE_SMS = 15;
     83     public static final int OP_RECEIVE_SMS = 16;
     84     public static final int OP_RECEIVE_EMERGECY_SMS = 17;
     85     public static final int OP_RECEIVE_MMS = 18;
     86     public static final int OP_RECEIVE_WAP_PUSH = 19;
     87     public static final int OP_SEND_SMS = 20;
     88     public static final int OP_READ_ICC_SMS = 21;
     89     public static final int OP_WRITE_ICC_SMS = 22;
     90     public static final int OP_WRITE_SETTINGS = 23;
     91     public static final int OP_SYSTEM_ALERT_WINDOW = 24;
     92     public static final int OP_ACCESS_NOTIFICATIONS = 25;
     93     public static final int OP_CAMERA = 26;
     94     public static final int OP_RECORD_AUDIO = 27;
     95     public static final int OP_PLAY_AUDIO = 28;
     96     public static final int OP_READ_CLIPBOARD = 29;
     97     public static final int OP_WRITE_CLIPBOARD = 30;
     98     /** @hide */
     99     public static final int _NUM_OP = 31;
    100 
    101     /**
    102      * This maps each operation to the operation that serves as the
    103      * switch to determine whether it is allowed.  Generally this is
    104      * a 1:1 mapping, but for some things (like location) that have
    105      * multiple low-level operations being tracked that should be
    106      * presented to hte user as one switch then this can be used to
    107      * make them all controlled by the same single operation.
    108      */
    109     private static int[] sOpToSwitch = new int[] {
    110             OP_COARSE_LOCATION,
    111             OP_COARSE_LOCATION,
    112             OP_COARSE_LOCATION,
    113             OP_VIBRATE,
    114             OP_READ_CONTACTS,
    115             OP_WRITE_CONTACTS,
    116             OP_READ_CALL_LOG,
    117             OP_WRITE_CALL_LOG,
    118             OP_READ_CALENDAR,
    119             OP_WRITE_CALENDAR,
    120             OP_COARSE_LOCATION,
    121             OP_POST_NOTIFICATION,
    122             OP_COARSE_LOCATION,
    123             OP_CALL_PHONE,
    124             OP_READ_SMS,
    125             OP_WRITE_SMS,
    126             OP_READ_SMS,
    127             OP_READ_SMS,
    128             OP_READ_SMS,
    129             OP_READ_SMS,
    130             OP_WRITE_SMS,
    131             OP_READ_SMS,
    132             OP_WRITE_SMS,
    133             OP_WRITE_SETTINGS,
    134             OP_SYSTEM_ALERT_WINDOW,
    135             OP_ACCESS_NOTIFICATIONS,
    136             OP_CAMERA,
    137             OP_RECORD_AUDIO,
    138             OP_PLAY_AUDIO,
    139             OP_READ_CLIPBOARD,
    140             OP_WRITE_CLIPBOARD,
    141     };
    142 
    143     /**
    144      * This provides a simple name for each operation to be used
    145      * in debug output.
    146      */
    147     private static String[] sOpNames = new String[] {
    148             "COARSE_LOCATION",
    149             "FINE_LOCATION",
    150             "GPS",
    151             "VIBRATE",
    152             "READ_CONTACTS",
    153             "WRITE_CONTACTS",
    154             "READ_CALL_LOG",
    155             "WRITE_CALL_LOG",
    156             "READ_CALENDAR",
    157             "WRITE_CALENDAR",
    158             "WIFI_SCAN",
    159             "POST_NOTIFICATION",
    160             "NEIGHBORING_CELLS",
    161             "CALL_PHONE",
    162             "READ_SMS",
    163             "WRITE_SMS",
    164             "RECEIVE_SMS",
    165             "RECEIVE_EMERGECY_SMS",
    166             "RECEIVE_MMS",
    167             "RECEIVE_WAP_PUSH",
    168             "SEND_SMS",
    169             "READ_ICC_SMS",
    170             "WRITE_ICC_SMS",
    171             "WRITE_SETTINGS",
    172             "SYSTEM_ALERT_WINDOW",
    173             "ACCESS_NOTIFICATIONS",
    174             "CAMERA",
    175             "RECORD_AUDIO",
    176             "PLAY_AUDIO",
    177             "READ_CLIPBOARD",
    178             "WRITE_CLIPBOARD",
    179     };
    180 
    181     /**
    182      * This optionally maps a permission to an operation.  If there
    183      * is no permission associated with an operation, it is null.
    184      */
    185     private static String[] sOpPerms = new String[] {
    186             android.Manifest.permission.ACCESS_COARSE_LOCATION,
    187             android.Manifest.permission.ACCESS_FINE_LOCATION,
    188             null,
    189             android.Manifest.permission.VIBRATE,
    190             android.Manifest.permission.READ_CONTACTS,
    191             android.Manifest.permission.WRITE_CONTACTS,
    192             android.Manifest.permission.READ_CALL_LOG,
    193             android.Manifest.permission.WRITE_CALL_LOG,
    194             android.Manifest.permission.READ_CALENDAR,
    195             android.Manifest.permission.WRITE_CALENDAR,
    196             null, // no permission required for notifications
    197             android.Manifest.permission.ACCESS_WIFI_STATE,
    198             null, // neighboring cells shares the coarse location perm
    199             android.Manifest.permission.CALL_PHONE,
    200             android.Manifest.permission.READ_SMS,
    201             android.Manifest.permission.WRITE_SMS,
    202             android.Manifest.permission.RECEIVE_SMS,
    203             android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST,
    204             android.Manifest.permission.RECEIVE_MMS,
    205             android.Manifest.permission.RECEIVE_WAP_PUSH,
    206             android.Manifest.permission.SEND_SMS,
    207             android.Manifest.permission.READ_SMS,
    208             android.Manifest.permission.WRITE_SMS,
    209             android.Manifest.permission.WRITE_SETTINGS,
    210             android.Manifest.permission.SYSTEM_ALERT_WINDOW,
    211             android.Manifest.permission.ACCESS_NOTIFICATIONS,
    212             android.Manifest.permission.CAMERA,
    213             android.Manifest.permission.RECORD_AUDIO,
    214             null, // no permission for playing audio
    215             null, // no permission for reading clipboard
    216             null, // no permission for writing clipboard
    217     };
    218 
    219     /**
    220      * Retrieve the op switch that controls the given operation.
    221      */
    222     public static int opToSwitch(int op) {
    223         return sOpToSwitch[op];
    224     }
    225 
    226     /**
    227      * Retrieve a non-localized name for the operation, for debugging output.
    228      */
    229     public static String opToName(int op) {
    230         if (op == OP_NONE) return "NONE";
    231         return op < sOpNames.length ? sOpNames[op] : ("Unknown(" + op + ")");
    232     }
    233 
    234     /**
    235      * Retrieve the permission associated with an operation, or null if there is not one.
    236      */
    237     public static String opToPermission(int op) {
    238         return sOpPerms[op];
    239     }
    240 
    241     /**
    242      * Class holding all of the operation information associated with an app.
    243      */
    244     public static class PackageOps implements Parcelable {
    245         private final String mPackageName;
    246         private final int mUid;
    247         private final List<OpEntry> mEntries;
    248 
    249         public PackageOps(String packageName, int uid, List<OpEntry> entries) {
    250             mPackageName = packageName;
    251             mUid = uid;
    252             mEntries = entries;
    253         }
    254 
    255         public String getPackageName() {
    256             return mPackageName;
    257         }
    258 
    259         public int getUid() {
    260             return mUid;
    261         }
    262 
    263         public List<OpEntry> getOps() {
    264             return mEntries;
    265         }
    266 
    267         @Override
    268         public int describeContents() {
    269             return 0;
    270         }
    271 
    272         @Override
    273         public void writeToParcel(Parcel dest, int flags) {
    274             dest.writeString(mPackageName);
    275             dest.writeInt(mUid);
    276             dest.writeInt(mEntries.size());
    277             for (int i=0; i<mEntries.size(); i++) {
    278                 mEntries.get(i).writeToParcel(dest, flags);
    279             }
    280         }
    281 
    282         PackageOps(Parcel source) {
    283             mPackageName = source.readString();
    284             mUid = source.readInt();
    285             mEntries = new ArrayList<OpEntry>();
    286             final int N = source.readInt();
    287             for (int i=0; i<N; i++) {
    288                 mEntries.add(OpEntry.CREATOR.createFromParcel(source));
    289             }
    290         }
    291 
    292         public static final Creator<PackageOps> CREATOR = new Creator<PackageOps>() {
    293             @Override public PackageOps createFromParcel(Parcel source) {
    294                 return new PackageOps(source);
    295             }
    296 
    297             @Override public PackageOps[] newArray(int size) {
    298                 return new PackageOps[size];
    299             }
    300         };
    301     }
    302 
    303     /**
    304      * Class holding the information about one unique operation of an application.
    305      */
    306     public static class OpEntry implements Parcelable {
    307         private final int mOp;
    308         private final int mMode;
    309         private final long mTime;
    310         private final long mRejectTime;
    311         private final int mDuration;
    312 
    313         public OpEntry(int op, int mode, long time, long rejectTime, int duration) {
    314             mOp = op;
    315             mMode = mode;
    316             mTime = time;
    317             mRejectTime = rejectTime;
    318             mDuration = duration;
    319         }
    320 
    321         public int getOp() {
    322             return mOp;
    323         }
    324 
    325         public int getMode() {
    326             return mMode;
    327         }
    328 
    329         public long getTime() {
    330             return mTime;
    331         }
    332 
    333         public long getRejectTime() {
    334             return mRejectTime;
    335         }
    336 
    337         public boolean isRunning() {
    338             return mDuration == -1;
    339         }
    340 
    341         public int getDuration() {
    342             return mDuration == -1 ? (int)(System.currentTimeMillis()-mTime) : mDuration;
    343         }
    344 
    345         @Override
    346         public int describeContents() {
    347             return 0;
    348         }
    349 
    350         @Override
    351         public void writeToParcel(Parcel dest, int flags) {
    352             dest.writeInt(mOp);
    353             dest.writeInt(mMode);
    354             dest.writeLong(mTime);
    355             dest.writeLong(mRejectTime);
    356             dest.writeInt(mDuration);
    357         }
    358 
    359         OpEntry(Parcel source) {
    360             mOp = source.readInt();
    361             mMode = source.readInt();
    362             mTime = source.readLong();
    363             mRejectTime = source.readLong();
    364             mDuration = source.readInt();
    365         }
    366 
    367         public static final Creator<OpEntry> CREATOR = new Creator<OpEntry>() {
    368             @Override public OpEntry createFromParcel(Parcel source) {
    369                 return new OpEntry(source);
    370             }
    371 
    372             @Override public OpEntry[] newArray(int size) {
    373                 return new OpEntry[size];
    374             }
    375         };
    376     }
    377 
    378     /**
    379      * Callback for notification of changes to operation state.
    380      */
    381     public interface Callback {
    382         public void opChanged(int op, String packageName);
    383     }
    384 
    385     public AppOpsManager(Context context, IAppOpsService service) {
    386         mContext = context;
    387         mService = service;
    388     }
    389 
    390     /**
    391      * Retrieve current operation state for all applications.
    392      *
    393      * @param ops The set of operations you are interested in, or null if you want all of them.
    394      */
    395     public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
    396         try {
    397             return mService.getPackagesForOps(ops);
    398         } catch (RemoteException e) {
    399         }
    400         return null;
    401     }
    402 
    403     /**
    404      * Retrieve current operation state for one application.
    405      *
    406      * @param uid The uid of the application of interest.
    407      * @param packageName The name of the application of interest.
    408      * @param ops The set of operations you are interested in, or null if you want all of them.
    409      */
    410     public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, int[] ops) {
    411         try {
    412             return mService.getOpsForPackage(uid, packageName, ops);
    413         } catch (RemoteException e) {
    414         }
    415         return null;
    416     }
    417 
    418     public void setMode(int code, int uid, String packageName, int mode) {
    419         try {
    420             mService.setMode(code, uid, packageName, mode);
    421         } catch (RemoteException e) {
    422         }
    423     }
    424 
    425     /** @hide */
    426     public void resetAllModes() {
    427         try {
    428             mService.resetAllModes();
    429         } catch (RemoteException e) {
    430         }
    431     }
    432 
    433     public void startWatchingMode(int op, String packageName, final Callback callback) {
    434         synchronized (mModeWatchers) {
    435             IAppOpsCallback cb = mModeWatchers.get(callback);
    436             if (cb == null) {
    437                 cb = new IAppOpsCallback.Stub() {
    438                     public void opChanged(int op, String packageName) {
    439                         callback.opChanged(op, packageName);
    440                     }
    441                 };
    442                 mModeWatchers.put(callback, cb);
    443             }
    444             try {
    445                 mService.startWatchingMode(op, packageName, cb);
    446             } catch (RemoteException e) {
    447             }
    448         }
    449     }
    450 
    451     public void stopWatchingMode(Callback callback) {
    452         synchronized (mModeWatchers) {
    453             IAppOpsCallback cb = mModeWatchers.get(callback);
    454             if (cb != null) {
    455                 try {
    456                     mService.stopWatchingMode(cb);
    457                 } catch (RemoteException e) {
    458                 }
    459             }
    460         }
    461     }
    462 
    463     public int checkOp(int op, int uid, String packageName) {
    464         try {
    465             int mode = mService.checkOperation(op, uid, packageName);
    466             if (mode == MODE_ERRORED) {
    467                 throw new SecurityException("Operation not allowed");
    468             }
    469             return mode;
    470         } catch (RemoteException e) {
    471         }
    472         return MODE_IGNORED;
    473     }
    474 
    475     public int checkOpNoThrow(int op, int uid, String packageName) {
    476         try {
    477             return mService.checkOperation(op, uid, packageName);
    478         } catch (RemoteException e) {
    479         }
    480         return MODE_IGNORED;
    481     }
    482 
    483     public int noteOp(int op, int uid, String packageName) {
    484         try {
    485             int mode = mService.noteOperation(op, uid, packageName);
    486             if (mode == MODE_ERRORED) {
    487                 throw new SecurityException("Operation not allowed");
    488             }
    489             return mode;
    490         } catch (RemoteException e) {
    491         }
    492         return MODE_IGNORED;
    493     }
    494 
    495     public int noteOpNoThrow(int op, int uid, String packageName) {
    496         try {
    497             return mService.noteOperation(op, uid, packageName);
    498         } catch (RemoteException e) {
    499         }
    500         return MODE_IGNORED;
    501     }
    502 
    503     public int noteOp(int op) {
    504         return noteOp(op, Process.myUid(), mContext.getBasePackageName());
    505     }
    506 
    507     public int startOp(int op, int uid, String packageName) {
    508         try {
    509             int mode = mService.startOperation(op, uid, packageName);
    510             if (mode == MODE_ERRORED) {
    511                 throw new SecurityException("Operation not allowed");
    512             }
    513             return mode;
    514         } catch (RemoteException e) {
    515         }
    516         return MODE_IGNORED;
    517     }
    518 
    519     public int startOpNoThrow(int op, int uid, String packageName) {
    520         try {
    521             return mService.startOperation(op, uid, packageName);
    522         } catch (RemoteException e) {
    523         }
    524         return MODE_IGNORED;
    525     }
    526 
    527     public int startOp(int op) {
    528         return startOp(op, Process.myUid(), mContext.getBasePackageName());
    529     }
    530 
    531     public void finishOp(int op, int uid, String packageName) {
    532         try {
    533             mService.finishOperation(op, uid, packageName);
    534         } catch (RemoteException e) {
    535         }
    536     }
    537 
    538     public void finishOp(int op) {
    539         finishOp(op, Process.myUid(), mContext.getBasePackageName());
    540     }
    541 }
    542