1 /*
2  * Copyright (C) 2022 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 com.android.server.tare;
18 
19 import android.Manifest;
20 import android.annotation.NonNull;
21 import android.content.pm.PackageManager;
22 import android.os.Binder;
23 
24 import com.android.modules.utils.BasicShellCommandHandler;
25 
26 import java.io.PrintWriter;
27 
28 /**
29  * Shell command handler for TARE.
30  */
31 public class TareShellCommand extends BasicShellCommandHandler {
32     static final int COMMAND_ERROR = -1;
33     static final int COMMAND_SUCCESS = 0;
34 
35     private final InternalResourceService mIrs;
36 
TareShellCommand(@onNull InternalResourceService irs)37     public TareShellCommand(@NonNull InternalResourceService irs) {
38         mIrs = irs;
39     }
40 
41     @Override
onCommand(String cmd)42     public int onCommand(String cmd) {
43         final PrintWriter pw = getOutPrintWriter();
44         try {
45             switch (cmd != null ? cmd : "") {
46                 case "clear-vip":
47                     return runClearVip(pw);
48                 case "set-vip":
49                     return runSetVip(pw);
50                 default:
51                     return handleDefaultCommands(cmd);
52             }
53         } catch (Exception e) {
54             pw.println("Exception: " + e);
55         }
56         return COMMAND_ERROR;
57     }
58 
59     @Override
onHelp()60     public void onHelp() {
61         final PrintWriter pw = getOutPrintWriter();
62 
63         pw.println("TARE commands:");
64         pw.println("  help");
65         pw.println("    Print this help text.");
66         pw.println("  clear-vip");
67         pw.println("    Clears all VIP settings resulting from previous calls using `set-vip` and");
68         pw.println("    resets them all to default.");
69         pw.println("  set-vip <USER_ID> <PACKAGE> <true|false|default>");
70         pw.println("    Designate the app as a Very Important Package or not. A VIP is allowed to");
71         pw.println("    do as much work as it wants, regardless of TARE state.");
72         pw.println("    The user ID must be an explicit user ID. USER_ALL, CURRENT, etc. are not");
73         pw.println("    supported.");
74         pw.println();
75     }
76 
checkPermission(@onNull String operation)77     private void checkPermission(@NonNull String operation) throws Exception {
78         final int perm = mIrs.getContext()
79                 .checkCallingOrSelfPermission(Manifest.permission.CHANGE_APP_IDLE_STATE);
80         if (perm != PackageManager.PERMISSION_GRANTED) {
81             throw new SecurityException("Uid " + Binder.getCallingUid()
82                     + " not permitted to " + operation);
83         }
84     }
85 
runClearVip(@onNull PrintWriter pw)86     private int runClearVip(@NonNull PrintWriter pw) throws Exception {
87         checkPermission("clear vip");
88 
89         final long ident = Binder.clearCallingIdentity();
90         try {
91             return mIrs.executeClearVip(pw);
92         } finally {
93             Binder.restoreCallingIdentity(ident);
94         }
95     }
96 
runSetVip(@onNull PrintWriter pw)97     private int runSetVip(@NonNull PrintWriter pw) throws Exception {
98         checkPermission("modify vip");
99 
100         final int userId = Integer.parseInt(getNextArgRequired());
101         final String pkgName = getNextArgRequired();
102         final String vipState = getNextArgRequired();
103         final Boolean isVip = "default".equals(vipState) ? null : Boolean.valueOf(vipState);
104 
105         final long ident = Binder.clearCallingIdentity();
106         try {
107             return mIrs.executeSetVip(pw, userId, pkgName, isVip);
108         } finally {
109             Binder.restoreCallingIdentity(ident);
110         }
111     }
112 }
113