1 /*
2  * Copyright (C) 2015 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.commands.sm;
18 
19 import android.os.IVoldTaskListener;
20 import android.os.PersistableBundle;
21 import android.os.RemoteException;
22 import android.os.ServiceManager;
23 import android.os.SystemProperties;
24 import android.os.storage.DiskInfo;
25 import android.os.storage.IStorageManager;
26 import android.os.storage.StorageManager;
27 import android.os.storage.VolumeInfo;
28 import android.util.Log;
29 
30 import java.util.concurrent.CompletableFuture;
31 
32 public final class Sm {
33     private static final String TAG = "Sm";
34     private static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
35             "persist.sys.vold_app_data_isolation_enabled";
36 
37     IStorageManager mSm;
38 
39     private String[] mArgs;
40     private int mNextArg;
41     private String mCurArgData;
42 
main(String[] args)43     public static void main(String[] args) {
44         boolean success = false;
45         try {
46             new Sm().run(args);
47             success = true;
48         } catch (Exception e) {
49             if (e instanceof IllegalArgumentException) {
50                 showUsage();
51                 System.exit(1);
52             }
53             Log.e(TAG, "Error", e);
54             System.err.println("Error: " + e);
55         }
56         System.exit(success ? 0 : 1);
57     }
58 
run(String[] args)59     public void run(String[] args) throws Exception {
60         if (args.length < 1) {
61             throw new IllegalArgumentException();
62         }
63 
64         mSm = IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
65         if (mSm == null) {
66             throw new RemoteException("Failed to find running mount service");
67         }
68 
69         mArgs = args;
70         String op = args[0];
71         mNextArg = 1;
72 
73         if ("list-disks".equals(op)) {
74             runListDisks();
75         } else if ("list-volumes".equals(op)) {
76             runListVolumes();
77         } else if ("has-adoptable".equals(op)) {
78             runHasAdoptable();
79         } else if ("get-primary-storage-uuid".equals(op)) {
80             runGetPrimaryStorageUuid();
81         } else if ("set-force-adoptable".equals(op)) {
82             runSetForceAdoptable();
83         } else if ("set-sdcardfs".equals(op)) {
84             runSetSdcardfs();
85         } else if ("partition".equals(op)) {
86             runPartition();
87         } else if ("mount".equals(op)) {
88             runMount();
89         } else if ("unmount".equals(op)) {
90             runUnmount();
91         } else if ("format".equals(op)) {
92             runFormat();
93         } else if ("benchmark".equals(op)) {
94             runBenchmark();
95         } else if ("forget".equals(op)) {
96             runForget();
97         } else if ("set-emulate-fbe".equals(op)) {
98             runSetEmulateFbe();
99         } else if ("get-fbe-mode".equals(op)) {
100             runGetFbeMode();
101         } else if ("idle-maint".equals(op)) {
102             runIdleMaint();
103         } else if ("fstrim".equals(op)) {
104             runFstrim();
105         } else if ("set-virtual-disk".equals(op)) {
106             runSetVirtualDisk();
107         } else if ("start-checkpoint".equals(op)) {
108             runStartCheckpoint();
109         } else if ("supports-checkpoint".equals(op)) {
110             runSupportsCheckpoint();
111         } else if ("unmount-app-data-dirs".equals(op)) {
112             runDisableAppDataIsolation();
113         } else {
114             throw new IllegalArgumentException();
115         }
116     }
117 
runListDisks()118     public void runListDisks() throws RemoteException {
119         final boolean onlyAdoptable = "adoptable".equals(nextArg());
120         final DiskInfo[] disks = mSm.getDisks();
121         for (DiskInfo disk : disks) {
122             if (!onlyAdoptable || disk.isAdoptable()) {
123                 System.out.println(disk.getId());
124             }
125         }
126     }
127 
runListVolumes()128     public void runListVolumes() throws RemoteException {
129         final String filter = nextArg();
130         final int filterType;
131         if ("public".equals(filter)) {
132             filterType = VolumeInfo.TYPE_PUBLIC;
133         } else if ("private".equals(filter)) {
134             filterType = VolumeInfo.TYPE_PRIVATE;
135         } else if ("emulated".equals(filter)) {
136             filterType = VolumeInfo.TYPE_EMULATED;
137         } else if ("stub".equals(filter)) {
138             filterType = VolumeInfo.TYPE_STUB;
139         } else {
140             filterType = -1;
141         }
142 
143         final VolumeInfo[] vols = mSm.getVolumes(0);
144         for (VolumeInfo vol : vols) {
145             if (filterType == -1 || filterType == vol.getType()) {
146                 final String envState = VolumeInfo.getEnvironmentForState(vol.getState());
147                 System.out.println(vol.getId() + " " + envState + " " + vol.getFsUuid());
148             }
149         }
150     }
151 
runHasAdoptable()152     public void runHasAdoptable() {
153         System.out.println(StorageManager.hasAdoptable());
154     }
155 
runGetPrimaryStorageUuid()156     public void runGetPrimaryStorageUuid() throws RemoteException {
157         System.out.println(mSm.getPrimaryStorageUuid());
158     }
159 
runSetForceAdoptable()160     public void runSetForceAdoptable() throws RemoteException {
161         final int mask = StorageManager.DEBUG_ADOPTABLE_FORCE_ON
162                 | StorageManager.DEBUG_ADOPTABLE_FORCE_OFF;
163         switch (nextArg()) {
164             case "on":
165             case "true":
166                 mSm.setDebugFlags(StorageManager.DEBUG_ADOPTABLE_FORCE_ON, mask);
167                 break;
168             case "off":
169                 mSm.setDebugFlags(StorageManager.DEBUG_ADOPTABLE_FORCE_OFF, mask);
170                 break;
171             case "default":
172             case "false":
173                 mSm.setDebugFlags(0, mask);
174                 break;
175         }
176     }
177 
runSetSdcardfs()178     public void runSetSdcardfs() throws RemoteException {
179         final int mask = StorageManager.DEBUG_SDCARDFS_FORCE_ON
180                 | StorageManager.DEBUG_SDCARDFS_FORCE_OFF;
181         switch (nextArg()) {
182             case "on":
183                 mSm.setDebugFlags(StorageManager.DEBUG_SDCARDFS_FORCE_ON, mask);
184                 break;
185             case "off":
186                 mSm.setDebugFlags(StorageManager.DEBUG_SDCARDFS_FORCE_OFF, mask);
187                 break;
188             case "default":
189                 mSm.setDebugFlags(0, mask);
190                 break;
191         }
192     }
193 
runSetEmulateFbe()194     public void runSetEmulateFbe() throws RemoteException {
195         final boolean emulateFbe = Boolean.parseBoolean(nextArg());
196         mSm.setDebugFlags(emulateFbe ? StorageManager.DEBUG_EMULATE_FBE : 0,
197                 StorageManager.DEBUG_EMULATE_FBE);
198     }
199 
runGetFbeMode()200     public void runGetFbeMode() {
201         if (StorageManager.isFileEncryptedNativeOnly()) {
202             System.out.println("native");
203         } else if (StorageManager.isFileEncryptedEmulatedOnly()) {
204             System.out.println("emulated");
205         } else {
206             System.out.println("none");
207         }
208     }
209 
runPartition()210     public void runPartition() throws RemoteException {
211         final String diskId = nextArg();
212         final String type = nextArg();
213         if ("public".equals(type)) {
214             mSm.partitionPublic(diskId);
215         } else if ("private".equals(type)) {
216             mSm.partitionPrivate(diskId);
217         } else if ("mixed".equals(type)) {
218             final int ratio = Integer.parseInt(nextArg());
219             mSm.partitionMixed(diskId, ratio);
220         } else {
221             throw new IllegalArgumentException("Unsupported partition type " + type);
222         }
223     }
224 
runMount()225     public void runMount() throws RemoteException {
226         final String volId = nextArg();
227         mSm.mount(volId);
228     }
229 
runUnmount()230     public void runUnmount() throws RemoteException {
231         final String volId = nextArg();
232         mSm.unmount(volId);
233     }
234 
runFormat()235     public void runFormat() throws RemoteException {
236         final String volId = nextArg();
237         mSm.format(volId);
238     }
239 
runBenchmark()240     public void runBenchmark() throws Exception {
241         final String volId = nextArg();
242         final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
243         mSm.benchmark(volId, new IVoldTaskListener.Stub() {
244             @Override
245             public void onStatus(int status, PersistableBundle extras) {
246                 // Ignored
247             }
248 
249             @Override
250             public void onFinished(int status, PersistableBundle extras) {
251                 // Touch to unparcel
252                 extras.size();
253                 result.complete(extras);
254             }
255         });
256         System.out.println(result.get());
257     }
258 
runDisableAppDataIsolation()259     public void runDisableAppDataIsolation() throws RemoteException {
260         if (!SystemProperties.getBoolean(
261                 ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false)) {
262             throw new IllegalStateException("Storage app data isolation is not enabled.");
263         }
264         final String pkgName = nextArg();
265         final int pid = Integer.parseInt(nextArg());
266         final int userId = Integer.parseInt(nextArg());
267         mSm.disableAppDataIsolation(pkgName, pid, userId);
268     }
269 
runForget()270     public void runForget() throws RemoteException {
271         final String fsUuid = nextArg();
272         if ("all".equals(fsUuid)) {
273             mSm.forgetAllVolumes();
274         } else {
275             mSm.forgetVolume(fsUuid);
276         }
277     }
278 
runFstrim()279     public void runFstrim() throws Exception {
280         final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
281         mSm.fstrim(0, new IVoldTaskListener.Stub() {
282             @Override
283             public void onStatus(int status, PersistableBundle extras) {
284                 // Ignored
285             }
286 
287             @Override
288             public void onFinished(int status, PersistableBundle extras) {
289                 // Touch to unparcel
290                 extras.size();
291                 result.complete(extras);
292             }
293         });
294         System.out.println(result.get());
295     }
296 
runSetVirtualDisk()297     public void runSetVirtualDisk() throws RemoteException {
298         final boolean virtualDisk = Boolean.parseBoolean(nextArg());
299         mSm.setDebugFlags(virtualDisk ? StorageManager.DEBUG_VIRTUAL_DISK : 0,
300                 StorageManager.DEBUG_VIRTUAL_DISK);
301     }
302 
runIdleMaint()303     public void runIdleMaint() throws RemoteException {
304         final boolean im_run = "run".equals(nextArg());
305         if (im_run) {
306             mSm.runIdleMaintenance();
307         } else {
308             mSm.abortIdleMaintenance();
309         }
310     }
311 
runStartCheckpoint()312     private void runStartCheckpoint() throws RemoteException {
313         final String numRetriesString = nextArg();
314         if (numRetriesString == null) {
315             throw new IllegalArgumentException("Expected <num-retries>");
316         }
317         int numRetries;
318         try {
319             numRetries = Integer.parseInt(numRetriesString);
320         } catch (NumberFormatException e) {
321             throw new IllegalArgumentException("<num-retries> must be a positive integer");
322         }
323         if (numRetries <= 0) {
324             throw new IllegalArgumentException("<num-retries> must be a positive integer");
325         }
326         mSm.startCheckpoint(numRetries);
327     }
328 
runSupportsCheckpoint()329     private void runSupportsCheckpoint() throws RemoteException {
330         System.out.println(mSm.supportsCheckpoint());
331     }
332 
nextArg()333     private String nextArg() {
334         if (mNextArg >= mArgs.length) {
335             return null;
336         }
337         String arg = mArgs[mNextArg];
338         mNextArg++;
339         return arg;
340     }
341 
showUsage()342     private static int showUsage() {
343         System.err.println("usage: sm list-disks [adoptable]");
344         System.err.println("       sm list-volumes [public|private|emulated|stub|all]");
345         System.err.println("       sm has-adoptable");
346         System.err.println("       sm get-primary-storage-uuid");
347         System.err.println("       sm set-force-adoptable [on|off|default]");
348         System.err.println("       sm set-virtual-disk [true|false]");
349         System.err.println("");
350         System.err.println("       sm partition DISK [public|private|mixed] [ratio]");
351         System.err.println("       sm mount VOLUME");
352         System.err.println("       sm unmount VOLUME");
353         System.err.println("       sm format VOLUME");
354         System.err.println("       sm benchmark VOLUME");
355         System.err.println("       sm idle-maint [run|abort]");
356         System.err.println("       sm fstrim");
357         System.err.println("");
358         System.err.println("       sm forget [UUID|all]");
359         System.err.println("");
360         System.err.println("       sm set-emulate-fbe [true|false]");
361         System.err.println("");
362         System.err.println("       sm start-checkpoint <num-retries>");
363         System.err.println("");
364         System.err.println("       sm supports-checkpoint");
365         System.err.println("");
366         System.err.println("       sm unmount-app-data-dirs PACKAGE_NAME PID USER_ID");
367         System.err.println("");
368         return 1;
369     }
370 }
371