Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2018 Google Inc.
      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 com.android.compatibility.common.util;
     18 
     19 import static android.app.AppOpsManager.MODE_ALLOWED;
     20 import static android.app.AppOpsManager.MODE_DEFAULT;
     21 import static android.app.AppOpsManager.MODE_ERRORED;
     22 import static android.app.AppOpsManager.MODE_IGNORED;
     23 
     24 import android.app.AppOpsManager;
     25 import android.support.test.InstrumentationRegistry;
     26 
     27 import java.io.IOException;
     28 
     29 /**
     30  * Utilities for controlling App Ops settings, and testing whether ops are logged.
     31  */
     32 public class AppOpsUtils {
     33 
     34     /**
     35      * Resets a package's app ops configuration to the device default. See AppOpsManager for the
     36      * default op settings.
     37      *
     38      * <p>
     39      * It's recommended to call this in setUp() and tearDown() of your test so the test starts and
     40      * ends with a reproducible default state, and so doesn't affect other tests.
     41      *
     42      * <p>
     43      * Some app ops are configured to be non-resettable, which means that the state of these will
     44      * not be reset even when calling this method.
     45      */
     46     public static String reset(String packageName) throws IOException {
     47         return runCommand("appops reset " + packageName);
     48     }
     49 
     50     /**
     51      * Sets the app op mode (e.g. allowed, denied) for a single package and operation.
     52      */
     53     public static String setOpMode(String packageName, String opStr, int mode)
     54             throws IOException {
     55         String modeStr;
     56         switch (mode) {
     57             case MODE_ALLOWED:
     58                 modeStr = "allow";
     59                 break;
     60             case MODE_ERRORED:
     61                 modeStr = "deny";
     62                 break;
     63             case MODE_IGNORED:
     64                 modeStr = "ignore";
     65                 break;
     66             case MODE_DEFAULT:
     67                 modeStr = "default";
     68                 break;
     69             default:
     70                 throw new IllegalArgumentException("Unexpected app op type");
     71         }
     72         String command = "appops set " + packageName + " " + opStr + " " + modeStr;
     73         return runCommand(command);
     74     }
     75 
     76     /**
     77      * Returns whether an allowed operation has been logged by the AppOpsManager for a
     78      * package. Operations are noted when the app attempts to perform them and calls e.g.
     79      * {@link AppOpsManager#noteOperation}.
     80      *
     81      * @param opStr The public string constant of the operation (e.g. OPSTR_READ_SMS).
     82      */
     83     public static boolean allowedOperationLogged(String packageName, String opStr)
     84             throws IOException {
     85         return getOpState(packageName, opStr).contains(" time=");
     86     }
     87 
     88     /**
     89      * Returns whether an allowed operation has been logged by the AppOpsManager for a
     90      * package. Operations are noted when the app attempts to perform them and calls e.g.
     91      * {@link AppOpsManager#noteOperation}.
     92      *
     93      * @param opStr The public string constant of the operation (e.g. OPSTR_READ_SMS).
     94      */
     95     public static boolean rejectedOperationLogged(String packageName, String opStr)
     96             throws IOException {
     97         return getOpState(packageName, opStr).contains(" rejectTime=");
     98     }
     99 
    100     /**
    101      * Returns the app op state for a package. Includes information on when the operation was last
    102      * attempted to be performed by the package.
    103      *
    104      * Format: "SEND_SMS: allow; time=+23h12m54s980ms ago; rejectTime=+1h10m23s180ms"
    105      */
    106     private static String getOpState(String packageName, String opStr) throws IOException {
    107         return runCommand("appops get " + packageName + " " + opStr);
    108     }
    109 
    110     private static String runCommand(String command) throws IOException {
    111         return SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), command);
    112     }
    113 }