17f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk/*
27f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk * Copyright (C) 2018 The Android Open Source Project
37f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk *
47f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
57f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk * except in compliance with the License. You may obtain a copy of the License at
67f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk *
77f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk *      http://www.apache.org/licenses/LICENSE-2.0
87f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk *
97f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk * Unless required by applicable law or agreed to in writing, software distributed under the
107f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
117f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk * KIND, either express or implied. See the License for the specific language governing
127f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk * permissions and limitations under the License.
137f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk */
147f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk
157f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monkpackage com.android.server.slice;
167f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk
177f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monkimport android.app.slice.SliceProvider;
187f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monkimport android.content.ContentResolver;
197f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monkimport android.content.Context;
207f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monkimport android.content.pm.PackageInfo;
217f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monkimport android.net.Uri;
227f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monkimport android.os.Binder;
237f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monkimport android.os.Bundle;
247f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monkimport android.os.Process;
257f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monkimport android.os.ShellCommand;
267f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monkimport android.util.ArraySet;
277f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk
287f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monkimport java.io.PrintWriter;
297f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monkimport java.util.List;
307f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monkimport java.util.Set;
317f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk
327f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monkpublic class SliceShellCommand extends ShellCommand {
337f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk
347f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk    private final SliceManagerService mService;
357f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk
367f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk    public SliceShellCommand(SliceManagerService service) {
377f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        mService = service;
387f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk    }
397f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk
407f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk    @Override
417f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk    public int onCommand(String cmd) {
427f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        if (cmd == null) {
437f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            return handleDefaultCommands(cmd);
447f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        }
457f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        switch (cmd) {
467f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            case "get-permissions":
477f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                return runGetPermissions(getNextArgRequired());
487f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        }
497f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        return 0;
507f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk    }
517f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk
527f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk    @Override
537f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk    public void onHelp() {
547f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        final PrintWriter pw = getOutPrintWriter();
557f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        pw.println("Status bar commands:");
567f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        pw.println("  help");
577f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        pw.println("    Print this help text.");
587f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        pw.println("");
597f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        pw.println("  get-permissions <authority>");
607f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        pw.println("    List the pkgs that have permission to an authority.");
617f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        pw.println("");
627f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk
637f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk    }
647f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk
657f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk    private int runGetPermissions(String authority) {
667f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        if (Binder.getCallingUid() != Process.SHELL_UID
677f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                && Binder.getCallingUid() != Process.ROOT_UID) {
687f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            getOutPrintWriter().println("Only shell can get permissions");
697f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            return -1;
707f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        }
717f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        Context context = mService.getContext();
727f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        long ident = Binder.clearCallingIdentity();
737f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        try {
747f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            Uri uri = new Uri.Builder()
757f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                    .scheme(ContentResolver.SCHEME_CONTENT)
767f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                    .authority(authority)
777f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                    .build();
787f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            if (!SliceProvider.SLICE_TYPE.equals(context.getContentResolver().getType(uri))) {
797f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                getOutPrintWriter().println(authority + " is not a slice provider");
807f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                return -1;
817f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            }
827f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            Bundle b = context.getContentResolver().call(uri, SliceProvider.METHOD_GET_PERMISSIONS,
837f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                    null, null);
847f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            if (b == null) {
857f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                getOutPrintWriter().println("An error occurred getting permissions");
867f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                return -1;
877f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            }
887f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            String[] permissions = b.getStringArray(SliceProvider.EXTRA_RESULT);
897f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            final PrintWriter pw = getOutPrintWriter();
907f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            Set<String> listedPackages = new ArraySet<>();
917f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            if (permissions != null && permissions.length != 0) {
927f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                List<PackageInfo> apps =
937f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                        context.getPackageManager().getPackagesHoldingPermissions(permissions, 0);
947f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                for (PackageInfo app : apps) {
957f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                    pw.println(app.packageName);
967f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                    listedPackages.add(app.packageName);
977f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                }
987f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            }
997f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            for (String pkg : mService.getAllPackagesGranted(authority)) {
1007f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                if (!listedPackages.contains(pkg)) {
1017f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                    pw.println(pkg);
1027f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                    listedPackages.add(pkg);
1037f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk                }
1047f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            }
1057f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        } finally {
1067f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk            Binder.restoreCallingIdentity(ident);
1077f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        }
1087f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk        return 0;
1097f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk    }
1107f01f3b6198465c70e81c5edcc1be2fa8199efd8Jason Monk}
111