1 /*
2  * Copyright (C) 2016 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.om;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.om.IOverlayManager;
22 import android.content.om.OverlayInfo;
23 import android.os.RemoteException;
24 import android.os.ShellCommand;
25 import android.os.UserHandle;
26 
27 import java.io.PrintWriter;
28 import java.util.List;
29 import java.util.Map;
30 
31 /**
32  * Implementation of 'cmd overlay' commands.
33  *
34  * This class provides an interface to the OverlayManagerService via adb.
35  * Intended only for manual debugging. Execute 'adb exec-out cmd overlay help'
36  * for a list of available commands.
37  */
38 final class OverlayManagerShellCommand extends ShellCommand {
39     private final IOverlayManager mInterface;
40 
OverlayManagerShellCommand(@onNull final IOverlayManager iom)41     OverlayManagerShellCommand(@NonNull final IOverlayManager iom) {
42         mInterface = iom;
43     }
44 
45     @Override
onCommand(@ullable final String cmd)46     public int onCommand(@Nullable final String cmd) {
47         if (cmd == null) {
48             return handleDefaultCommands(cmd);
49         }
50         final PrintWriter err = getErrPrintWriter();
51         try {
52             switch (cmd) {
53                 case "list":
54                     return runList();
55                 case "enable":
56                     return runEnableDisable(true);
57                 case "disable":
58                     return runEnableDisable(false);
59                 case "enable-exclusive":
60                     return runEnableExclusive();
61                 case "set-priority":
62                     return runSetPriority();
63                 default:
64                     return handleDefaultCommands(cmd);
65             }
66         } catch (IllegalArgumentException e) {
67             err.println("Error: " + e.getMessage());
68         } catch (RemoteException e) {
69             err.println("Remote exception: " + e);
70         }
71         return -1;
72     }
73 
74     @Override
onHelp()75     public void onHelp() {
76         final PrintWriter out = getOutPrintWriter();
77         out.println("Overlay manager (overlay) commands:");
78         out.println("  help");
79         out.println("    Print this help text.");
80         out.println("  dump [--verbose] [--user USER_ID] [PACKAGE [PACKAGE [...]]]");
81         out.println("    Print debugging information about the overlay manager.");
82         out.println("  list [--user USER_ID] [PACKAGE [PACKAGE [...]]]");
83         out.println("    Print information about target and overlay packages.");
84         out.println("    Overlay packages are printed in priority order. With optional");
85         out.println("    parameters PACKAGEs, limit output to the specified packages");
86         out.println("    but include more information about each package.");
87         out.println("  enable [--user USER_ID] PACKAGE");
88         out.println("    Enable overlay package PACKAGE.");
89         out.println("  disable [--user USER_ID] PACKAGE");
90         out.println("    Disable overlay package PACKAGE.");
91         out.println("  enable-exclusive [--user USER_ID] [--category] PACKAGE");
92         out.println("    Enable overlay package PACKAGE and disable all other overlays for");
93         out.println("    its target package. If the --category option is given, only disables");
94         out.println("    other overlays in the same category.");
95         out.println("  set-priority [--user USER_ID] PACKAGE PARENT|lowest|highest");
96         out.println("    Change the priority of the overlay PACKAGE to be just higher than");
97         out.println("    the priority of PACKAGE_PARENT If PARENT is the special keyword");
98         out.println("    'lowest', change priority of PACKAGE to the lowest priority.");
99         out.println("    If PARENT is the special keyword 'highest', change priority of");
100         out.println("    PACKAGE to the highest priority.");
101     }
102 
runList()103     private int runList() throws RemoteException {
104         final PrintWriter out = getOutPrintWriter();
105         final PrintWriter err = getErrPrintWriter();
106 
107         int userId = UserHandle.USER_SYSTEM;
108         String opt;
109         while ((opt = getNextOption()) != null) {
110             switch (opt) {
111                 case "--user":
112                     userId = UserHandle.parseUserArg(getNextArgRequired());
113                     break;
114                 default:
115                     err.println("Error: Unknown option: " + opt);
116                     return 1;
117             }
118         }
119 
120         final Map<String, List<OverlayInfo>> allOverlays = mInterface.getAllOverlays(userId);
121         for (final String targetPackageName : allOverlays.keySet()) {
122             out.println(targetPackageName);
123             List<OverlayInfo> overlaysForTarget = allOverlays.get(targetPackageName);
124             final int N = overlaysForTarget.size();
125             for (int i = 0; i < N; i++) {
126                 final OverlayInfo oi = overlaysForTarget.get(i);
127                 String status;
128                 switch (oi.state) {
129                     case OverlayInfo.STATE_ENABLED_STATIC:
130                     case OverlayInfo.STATE_ENABLED:
131                         status = "[x]";
132                         break;
133                     case OverlayInfo.STATE_DISABLED:
134                         status = "[ ]";
135                         break;
136                     default:
137                         status = "---";
138                         break;
139                 }
140                 out.println(String.format("%s %s", status, oi.packageName));
141             }
142             out.println();
143         }
144         return 0;
145     }
146 
runEnableDisable(final boolean enable)147     private int runEnableDisable(final boolean enable) throws RemoteException {
148         final PrintWriter err = getErrPrintWriter();
149 
150         int userId = UserHandle.USER_SYSTEM;
151         String opt;
152         while ((opt = getNextOption()) != null) {
153             switch (opt) {
154                 case "--user":
155                     userId = UserHandle.parseUserArg(getNextArgRequired());
156                     break;
157                 default:
158                     err.println("Error: Unknown option: " + opt);
159                     return 1;
160             }
161         }
162 
163         final String packageName = getNextArgRequired();
164         return mInterface.setEnabled(packageName, enable, userId) ? 0 : 1;
165     }
166 
runEnableExclusive()167     private int runEnableExclusive() throws RemoteException {
168         final PrintWriter err = getErrPrintWriter();
169 
170         int userId = UserHandle.USER_SYSTEM;
171         boolean inCategory = false;
172         String opt;
173         while ((opt = getNextOption()) != null) {
174             switch (opt) {
175                 case "--user":
176                     userId = UserHandle.parseUserArg(getNextArgRequired());
177                     break;
178                 case "--category":
179                     inCategory = true;
180                     break;
181                 default:
182                     err.println("Error: Unknown option: " + opt);
183                     return 1;
184             }
185         }
186         final String overlay = getNextArgRequired();
187         if (inCategory) {
188             return mInterface.setEnabledExclusiveInCategory(overlay, userId) ? 0 : 1;
189         } else {
190             return mInterface.setEnabledExclusive(overlay, true, userId) ? 0 : 1;
191         }
192     }
193 
runSetPriority()194     private int runSetPriority() throws RemoteException {
195         final PrintWriter err = getErrPrintWriter();
196 
197         int userId = UserHandle.USER_SYSTEM;
198         String opt;
199         while ((opt = getNextOption()) != null) {
200             switch (opt) {
201                 case "--user":
202                     userId = UserHandle.parseUserArg(getNextArgRequired());
203                     break;
204                 default:
205                     err.println("Error: Unknown option: " + opt);
206                     return 1;
207             }
208         }
209 
210         final String packageName = getNextArgRequired();
211         final String newParentPackageName = getNextArgRequired();
212 
213         if ("highest".equals(newParentPackageName)) {
214             return mInterface.setHighestPriority(packageName, userId) ? 0 : 1;
215         } else if ("lowest".equals(newParentPackageName)) {
216             return mInterface.setLowestPriority(packageName, userId) ? 0 : 1;
217         } else {
218             return mInterface.setPriority(packageName, newParentPackageName, userId) ? 0 : 1;
219         }
220     }
221 }
222