AutofillManagerServiceShellCommand.java revision 9f9ee25515591ef33281708c0ab911962f4364a6
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
17package com.android.server.autofill;
18
19import static com.android.server.autofill.AutofillManagerService.RECEIVER_BUNDLE_EXTRA_SESSIONS;
20
21import android.os.Bundle;
22import android.os.ShellCommand;
23import android.os.UserHandle;
24import android.view.autofill.AutofillManager;
25
26import com.android.internal.os.IResultReceiver;
27
28import java.io.PrintWriter;
29import java.util.ArrayList;
30import java.util.concurrent.CountDownLatch;
31import java.util.concurrent.TimeUnit;
32
33public final class AutofillManagerServiceShellCommand extends ShellCommand {
34
35    private final AutofillManagerService mService;
36
37    public AutofillManagerServiceShellCommand(AutofillManagerService service) {
38        mService = service;
39    }
40
41    @Override
42    public int onCommand(String cmd) {
43        if (cmd == null) {
44            return handleDefaultCommands(cmd);
45        }
46        final PrintWriter pw = getOutPrintWriter();
47        switch (cmd) {
48            case "list":
49                return requestList(pw);
50            case "destroy":
51                return requestDestroy(pw);
52            case "reset":
53                return requestReset();
54            case "get":
55                return requestGet(pw);
56            case "set":
57                return requestSet(pw);
58            default:
59                return handleDefaultCommands(cmd);
60        }
61    }
62
63    @Override
64    public void onHelp() {
65        try (final PrintWriter pw = getOutPrintWriter();) {
66            pw.println("AutoFill Service (autofill) commands:");
67            pw.println("  help");
68            pw.println("    Prints this help text.");
69            pw.println("");
70            pw.println("  get log_level ");
71            pw.println("    Gets the Autofill log level (off | debug | verbose).");
72            pw.println("");
73            pw.println("  set log_level [off | debug | verbose]");
74            pw.println("    Sets the Autofill log level.");
75            pw.println("");
76            pw.println("  list sessions [--user USER_ID]");
77            pw.println("    List all pending sessions.");
78            pw.println("");
79            pw.println("  destroy sessions [--user USER_ID]");
80            pw.println("    Destroy all pending sessions.");
81            pw.println("");
82            pw.println("  reset");
83            pw.println("    Reset all pending sessions and cached service connections.");
84            pw.println("");
85        }
86    }
87
88    private int requestGet(PrintWriter pw) {
89        if (!isNextArgLogLevel(pw, "get")) {
90            return -1;
91        }
92        final int logLevel = mService.getLogLevel();
93        switch (logLevel) {
94            case AutofillManager.FLAG_ADD_CLIENT_VERBOSE:
95                pw.println("verbose");
96                return 0;
97            case AutofillManager.FLAG_ADD_CLIENT_DEBUG:
98                pw.println("debug");
99                return 0;
100            case 0:
101                pw.println("off");
102                return 0;
103            default:
104                pw.println("unknow (" + logLevel + ")");
105                return 0;
106        }
107    }
108
109    private int requestSet(PrintWriter pw) {
110        if (!isNextArgLogLevel(pw, "set")) {
111            return -1;
112        }
113        final String logLevel = getNextArg();
114        switch (logLevel.toLowerCase()) {
115            case "verbose":
116                mService.setLogLevel(AutofillManager.FLAG_ADD_CLIENT_VERBOSE);
117                return 0;
118            case "debug":
119                mService.setLogLevel(AutofillManager.FLAG_ADD_CLIENT_DEBUG);
120                return 0;
121            case "off":
122                mService.setLogLevel(0);
123                return 0;
124            default:
125                pw.println("Invalid level: " + logLevel);
126                return -1;
127        }
128    }
129
130    private int requestDestroy(PrintWriter pw) {
131        if (!isNextArgSessions(pw)) {
132            return -1;
133        }
134
135        final int userId = getUserIdFromArgsOrAllUsers();
136        final CountDownLatch latch = new CountDownLatch(1);
137        final IResultReceiver receiver = new IResultReceiver.Stub() {
138            @Override
139            public void send(int resultCode, Bundle resultData) {
140                latch.countDown();
141            }
142        };
143        return requestSessionCommon(pw, latch, () -> mService.destroySessions(userId, receiver));
144    }
145
146    private int requestList(PrintWriter pw) {
147        if (!isNextArgSessions(pw)) {
148            return -1;
149        }
150
151        final int userId = getUserIdFromArgsOrAllUsers();
152        final CountDownLatch latch = new CountDownLatch(1);
153        final IResultReceiver receiver = new IResultReceiver.Stub() {
154            @Override
155            public void send(int resultCode, Bundle resultData) {
156                final ArrayList<String> sessions = resultData
157                        .getStringArrayList(RECEIVER_BUNDLE_EXTRA_SESSIONS);
158                for (String session : sessions) {
159                    pw.println(session);
160                }
161                latch.countDown();
162            }
163        };
164        return requestSessionCommon(pw, latch, () -> mService.listSessions(userId, receiver));
165    }
166
167    private boolean isNextArgSessions(PrintWriter pw) {
168        final String type = getNextArgRequired();
169        if (!type.equals("sessions")) {
170            pw.println("Error: invalid list type");
171            return false;
172        }
173        return true;
174    }
175
176    private boolean isNextArgLogLevel(PrintWriter pw, String cmd) {
177        final String type = getNextArgRequired();
178        if (!type.equals("log_level")) {
179            pw.println("Error: invalid " + cmd + " type: " + type);
180            return false;
181        }
182        return true;
183    }
184
185    private int requestSessionCommon(PrintWriter pw, CountDownLatch latch,
186            Runnable command) {
187        command.run();
188
189        try {
190            final boolean received = latch.await(5, TimeUnit.SECONDS);
191            if (!received) {
192                pw.println("Timed out after 5 seconds");
193                return -1;
194            }
195        } catch (InterruptedException e) {
196            pw.println("System call interrupted");
197            Thread.currentThread().interrupt();
198            return -1;
199        }
200        return 0;
201    }
202
203    private int requestReset() {
204        mService.reset();
205        return 0;
206    }
207
208    private int getUserIdFromArgsOrAllUsers() {
209        if ("--user".equals(getNextArg())) {
210            return UserHandle.parseUserArg(getNextArgRequired());
211        }
212        return UserHandle.USER_ALL;
213    }
214}
215