diff options
6 files changed, 251 insertions, 47 deletions
diff --git a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java index 267cb365748e..eec7be22c78b 100644 --- a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java +++ b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java @@ -177,6 +177,23 @@ public class InstallOverlayTests extends BaseHostJUnit4Test { .contains(APP_OVERLAY_PACKAGE_NAME)); } + @Test + public void testAdbShellOMSInterface() throws Exception { + installPackage("OverlayHostTests_AppOverlayV1.apk"); + assertTrue(shell("cmd overlay list " + DEVICE_TEST_PKG).contains(DEVICE_TEST_PKG)); + assertTrue(shell("cmd overlay list " + DEVICE_TEST_PKG).contains(APP_OVERLAY_PACKAGE_NAME)); + assertEquals("[ ] " + APP_OVERLAY_PACKAGE_NAME, + shell("cmd overlay list " + APP_OVERLAY_PACKAGE_NAME).trim()); + assertEquals("STATE_DISABLED", + shell("cmd overlay dump state " + APP_OVERLAY_PACKAGE_NAME).trim()); + + setOverlayEnabled(APP_OVERLAY_PACKAGE_NAME, true); + assertEquals("[x] " + APP_OVERLAY_PACKAGE_NAME, + shell("cmd overlay list " + APP_OVERLAY_PACKAGE_NAME).trim()); + assertEquals("STATE_ENABLED", + shell("cmd overlay dump state " + APP_OVERLAY_PACKAGE_NAME).trim()); + } + private void delay() { try { Thread.sleep(1000); @@ -195,20 +212,24 @@ public class InstallOverlayTests extends BaseHostJUnit4Test { } private void installConvertExistingInstantPackageToFull(String pkg) throws Exception { - getDevice().executeShellCommand("cmd package install-existing --wait --full " + pkg); + shell("cmd package install-existing --wait --full " + pkg); } private void setPackageEnabled(String pkg, boolean enabled) throws Exception { - getDevice().executeShellCommand("cmd package " + (enabled ? "enable " : "disable ") + pkg); + shell("cmd package " + (enabled ? "enable " : "disable ") + pkg); delay(); } private void setOverlayEnabled(String pkg, boolean enabled) throws Exception { - getDevice().executeShellCommand("cmd overlay " + (enabled ? "enable " : "disable ") + pkg); + shell("cmd overlay " + (enabled ? "enable " : "disable ") + pkg); delay(); } private boolean overlayManagerContainsPackage(String pkg) throws Exception { - return getDevice().executeShellCommand("cmd overlay list").contains(pkg); + return shell("cmd overlay list").contains(pkg); + } + + private String shell(final String cmd) throws Exception { + return getDevice().executeShellCommand(cmd); } } diff --git a/services/core/java/com/android/server/om/DumpState.java b/services/core/java/com/android/server/om/DumpState.java new file mode 100644 index 000000000000..1e2e054bbc6c --- /dev/null +++ b/services/core/java/com/android/server/om/DumpState.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.om; + +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.os.UserHandle; + +/** + * State for dumps performed by the OverlayManagerService. + */ +public final class DumpState { + @UserIdInt private int mUserId = UserHandle.USER_ALL; + @Nullable private String mPackageName; + @Nullable private String mField; + private boolean mVerbose; + + /** Sets the user to dump the state for */ + public void setUserId(@UserIdInt int userId) { + mUserId = userId; + } + @UserIdInt public int getUserId() { + return mUserId; + } + + /** Sets the name of the package to dump the state for */ + public void setPackageName(String packageName) { + mPackageName = packageName; + } + @Nullable public String getPackageName() { + return mPackageName; + } + + /** Sets the name of the field to dump the state of */ + public void setField(String field) { + mField = field; + } + @Nullable public String getField() { + return mField; + } + + /** Enables verbose dump state */ + public void setVerbose(boolean verbose) { + mVerbose = verbose; + } + public boolean isVerbose() { + return mVerbose; + } +} diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index 209ccdae75d0..da69986cd59f 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -749,15 +749,77 @@ public final class OverlayManagerService extends SystemService { } @Override - protected void dump(@NonNull final FileDescriptor fd, @NonNull final PrintWriter pw, - @NonNull final String[] argv) { - enforceDumpPermission("dump"); - - final boolean verbose = argv.length > 0 && "--verbose".equals(argv[0]); + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + final DumpState dumpState = new DumpState(); + dumpState.setUserId(UserHandle.getUserId(Binder.getCallingUid())); + + int opti = 0; + while (opti < args.length) { + final String opt = args[opti]; + if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') { + break; + } + opti++; + + if ("-h".equals(opt)) { + pw.println("dump [-h] [--verbose] [--user USER_ID] [[FIELD] PACKAGE]"); + pw.println(" Print debugging information about the overlay manager."); + pw.println(" With optional parameter PACKAGE, limit output to the specified"); + pw.println(" package. With optional parameter FIELD, limit output to"); + pw.println(" the value of that SettingsItem field. Field names are"); + pw.println(" case insensitive and out.println the m prefix can be omitted,"); + pw.println(" so the following are equivalent: mState, mstate, State, state."); + return; + } else if ("--user".equals(opt)) { + opti++; + if (opti >= args.length) { + pw.println("Error: user missing argument"); + return; + } + try { + dumpState.setUserId(Integer.parseInt(args[opti])); + } catch (NumberFormatException e) { + pw.println("Error: user argument is not a number: " + args[opti]); + return; + } + } else if ("--verbose".equals(opt)) { + dumpState.setVerbose(true); + } else { + pw.println("Unknown argument: " + opt + "; use -h for help"); + } + } + if (opti < args.length) { + final String arg = args[opti]; + opti++; + switch (arg) { + case "packagename": + case "userid": + case "targetpackagename": + case "targetoverlayablename": + case "basecodepath": + case "state": + case "isenabled": + case "isstatic": + case "priority": + case "category": + dumpState.setField(arg); + break; + default: + dumpState.setPackageName(arg); + break; + } + } + if (dumpState.getPackageName() == null && opti < args.length) { + dumpState.setPackageName(args[opti]); + opti++; + } + enforceDumpPermission("dump"); synchronized (mLock) { - mImpl.onDump(pw); - mPackageManager.dump(pw, verbose); + mImpl.dump(pw, dumpState); + if (dumpState.getPackageName() == null) { + mPackageManager.dump(pw, dumpState); + } } } @@ -1046,10 +1108,10 @@ public final class OverlayManagerService extends SystemService { private static final String TAB1 = " "; private static final String TAB2 = TAB1 + TAB1; - public void dump(@NonNull final PrintWriter pw, final boolean verbose) { + public void dump(@NonNull final PrintWriter pw, @NonNull DumpState dumpState) { pw.println("PackageInfo cache"); - if (!verbose) { + if (!dumpState.isVerbose()) { int count = 0; final int n = mCache.size(); for (int i = 0; i < n; i++) { diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index 092dbc817e32..6f28675d051b 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -636,9 +636,11 @@ final class OverlayManagerServiceImpl { return true; } - void onDump(@NonNull final PrintWriter pw) { - mSettings.dump(pw); - pw.println("Default overlays: " + TextUtils.join(";", mDefaultOverlays)); + void dump(@NonNull final PrintWriter pw, @NonNull DumpState dumpState) { + mSettings.dump(pw, dumpState); + if (dumpState.getPackageName() == null) { + pw.println("Default overlays: " + TextUtils.join(";", mDefaultOverlays)); + } } @NonNull String[] getDefaultOverlayPackages() { diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java index f35c70780db9..b7346d455319 100644 --- a/services/core/java/com/android/server/om/OverlayManagerSettings.java +++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java @@ -22,6 +22,7 @@ import static com.android.server.om.OverlayManagerService.TAG; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.om.OverlayInfo; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.Slog; import android.util.Xml; @@ -288,35 +289,78 @@ final class OverlayManagerSettings { return true; } - void dump(@NonNull final PrintWriter p) { + void dump(@NonNull final PrintWriter p, @NonNull DumpState dumpState) { + // select items to display + Stream<SettingsItem> items = mItems.stream(); + if (dumpState.getUserId() != UserHandle.USER_ALL) { + items = items.filter(item -> item.mUserId == dumpState.getUserId()); + } + if (dumpState.getPackageName() != null) { + items = items.filter(item -> item.mPackageName.equals(dumpState.getPackageName())); + } + + // display items final IndentingPrintWriter pw = new IndentingPrintWriter(p, " "); - pw.println("Settings"); + if (dumpState.getField() != null) { + items.forEach(item -> dumpSettingsItemField(pw, item, dumpState.getField())); + } else { + items.forEach(item -> dumpSettingsItem(pw, item)); + } + } + + private void dumpSettingsItem(@NonNull final IndentingPrintWriter pw, + @NonNull final SettingsItem item) { + pw.println(item.mPackageName + ":" + item.getUserId() + " {"); pw.increaseIndent(); - if (mItems.isEmpty()) { - pw.println("<none>"); - return; - } + pw.println("mPackageName...........: " + item.mPackageName); + pw.println("mUserId................: " + item.getUserId()); + pw.println("mTargetPackageName.....: " + item.getTargetPackageName()); + pw.println("mTargetOverlayableName.: " + item.getTargetOverlayableName()); + pw.println("mBaseCodePath..........: " + item.getBaseCodePath()); + pw.println("mState.................: " + OverlayInfo.stateToString(item.getState())); + pw.println("mIsEnabled.............: " + item.isEnabled()); + pw.println("mIsStatic..............: " + item.isStatic()); + pw.println("mPriority..............: " + item.mPriority); + pw.println("mCategory..............: " + item.mCategory); + + pw.decreaseIndent(); + pw.println("}"); + } - final int n = mItems.size(); - for (int i = 0; i < n; i++) { - final SettingsItem item = mItems.get(i); - pw.println(item.mPackageName + ":" + item.getUserId() + " {"); - pw.increaseIndent(); - - pw.println("mPackageName...........: " + item.mPackageName); - pw.println("mUserId................: " + item.getUserId()); - pw.println("mTargetPackageName.....: " + item.getTargetPackageName()); - pw.println("mTargetOverlayableName.: " + item.getTargetOverlayableName()); - pw.println("mBaseCodePath..........: " + item.getBaseCodePath()); - pw.println("mState.................: " + OverlayInfo.stateToString(item.getState())); - pw.println("mIsEnabled.............: " + item.isEnabled()); - pw.println("mIsStatic..............: " + item.isStatic()); - pw.println("mPriority..............: " + item.mPriority); - pw.println("mCategory..............: " + item.mCategory); - - pw.decreaseIndent(); - pw.println("}"); + private void dumpSettingsItemField(@NonNull final IndentingPrintWriter pw, + @NonNull final SettingsItem item, @NonNull final String field) { + switch (field) { + case "packagename": + pw.println(item.mPackageName); + break; + case "userid": + pw.println(item.mUserId); + break; + case "targetpackagename": + pw.println(item.mTargetPackageName); + break; + case "targetoverlayablename": + pw.println(item.mTargetOverlayableName); + break; + case "basecodepath": + pw.println(item.mBaseCodePath); + break; + case "state": + pw.println(OverlayInfo.stateToString(item.mState)); + break; + case "isenabled": + pw.println(item.mIsEnabled); + break; + case "isstatic": + pw.println(item.mIsStatic); + break; + case "priority": + pw.println(item.mPriority); + break; + case "category": + pw.println(item.mCategory); + break; } } diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java index e2b1cba3819f..7ee167adfd38 100644 --- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java +++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java @@ -77,13 +77,17 @@ final class OverlayManagerShellCommand extends ShellCommand { out.println("Overlay manager (overlay) commands:"); out.println(" help"); out.println(" Print this help text."); - out.println(" dump [--verbose] [--user USER_ID] [PACKAGE [PACKAGE [...]]]"); + out.println(" dump [--verbose] [--user USER_ID] [[FIELD] PACKAGE]"); out.println(" Print debugging information about the overlay manager."); - out.println(" list [--user USER_ID] [PACKAGE [PACKAGE [...]]]"); + out.println(" With optional parameter PACKAGE, limit output to the specified"); + out.println(" package. With optional parameter FIELD, limit output to"); + out.println(" the value of that SettingsItem field. Field names are"); + out.println(" case insensitive and out.println the m prefix can be omitted,"); + out.println(" so the following are equivalent: mState, mstate, State, state."); + out.println(" list [--user USER_ID] [PACKAGE]"); out.println(" Print information about target and overlay packages."); out.println(" Overlay packages are printed in priority order. With optional"); - out.println(" parameters PACKAGEs, limit output to the specified packages"); - out.println(" but include more information about each package."); + out.println(" parameter PACKAGE, limit output to the specified package."); out.println(" enable [--user USER_ID] PACKAGE"); out.println(" Enable overlay package PACKAGE."); out.println(" disable [--user USER_ID] PACKAGE"); @@ -116,14 +120,20 @@ final class OverlayManagerShellCommand extends ShellCommand { return 1; } } + final String packageName = getNextArg(); final Map<String, List<OverlayInfo>> allOverlays = mInterface.getAllOverlays(userId); for (final String targetPackageName : allOverlays.keySet()) { - out.println(targetPackageName); + if (targetPackageName.equals(packageName)) { + out.println(targetPackageName); + } List<OverlayInfo> overlaysForTarget = allOverlays.get(targetPackageName); final int n = overlaysForTarget.size(); for (int i = 0; i < n; i++) { final OverlayInfo oi = overlaysForTarget.get(i); + if (!targetPackageName.equals(packageName) && !oi.packageName.equals(packageName)) { + continue; + } String status; switch (oi.state) { case OverlayInfo.STATE_ENABLED_STATIC: @@ -139,7 +149,9 @@ final class OverlayManagerShellCommand extends ShellCommand { } out.println(String.format("%s %s", status, oi.packageName)); } - out.println(); + if (targetPackageName.equals(packageName)) { + out.println(); + } } return 0; } |