Loading core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java +25 −4 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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); } } services/core/java/com/android/server/om/DumpState.java 0 → 100644 +63 −0 Original line number Diff line number Diff line /* * 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; } } services/core/java/com/android/server/om/OverlayManagerService.java +71 −9 Original line number Diff line number Diff line Loading @@ -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"); 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++; final boolean verbose = argv.length > 0 && "--verbose".equals(argv[0]); 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); } } } Loading Loading @@ -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++) { Loading services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +5 −3 Original line number Diff line number Diff line Loading @@ -636,10 +636,12 @@ final class OverlayManagerServiceImpl { return true; } void onDump(@NonNull final PrintWriter pw) { mSettings.dump(pw); 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() { return mDefaultOverlays; Loading services/core/java/com/android/server/om/OverlayManagerSettings.java +69 −25 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -288,19 +289,27 @@ final class OverlayManagerSettings { return true; } void dump(@NonNull final PrintWriter p) { final IndentingPrintWriter pw = new IndentingPrintWriter(p, " "); pw.println("Settings"); pw.increaseIndent(); 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())); } if (mItems.isEmpty()) { pw.println("<none>"); return; // display items final IndentingPrintWriter pw = new IndentingPrintWriter(p, " "); if (dumpState.getField() != null) { items.forEach(item -> dumpSettingsItemField(pw, item, dumpState.getField())); } else { items.forEach(item -> dumpSettingsItem(pw, item)); } } final int n = mItems.size(); for (int i = 0; i < n; i++) { final SettingsItem item = mItems.get(i); private void dumpSettingsItem(@NonNull final IndentingPrintWriter pw, @NonNull final SettingsItem item) { pw.println(item.mPackageName + ":" + item.getUserId() + " {"); pw.increaseIndent(); Loading @@ -318,6 +327,41 @@ final class OverlayManagerSettings { 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; } } void restore(@NonNull final InputStream is) throws IOException, XmlPullParserException { Loading Loading
core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java +25 −4 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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); } }
services/core/java/com/android/server/om/DumpState.java 0 → 100644 +63 −0 Original line number Diff line number Diff line /* * 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; } }
services/core/java/com/android/server/om/OverlayManagerService.java +71 −9 Original line number Diff line number Diff line Loading @@ -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"); 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++; final boolean verbose = argv.length > 0 && "--verbose".equals(argv[0]); 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); } } } Loading Loading @@ -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++) { Loading
services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +5 −3 Original line number Diff line number Diff line Loading @@ -636,10 +636,12 @@ final class OverlayManagerServiceImpl { return true; } void onDump(@NonNull final PrintWriter pw) { mSettings.dump(pw); 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() { return mDefaultOverlays; Loading
services/core/java/com/android/server/om/OverlayManagerSettings.java +69 −25 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -288,19 +289,27 @@ final class OverlayManagerSettings { return true; } void dump(@NonNull final PrintWriter p) { final IndentingPrintWriter pw = new IndentingPrintWriter(p, " "); pw.println("Settings"); pw.increaseIndent(); 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())); } if (mItems.isEmpty()) { pw.println("<none>"); return; // display items final IndentingPrintWriter pw = new IndentingPrintWriter(p, " "); if (dumpState.getField() != null) { items.forEach(item -> dumpSettingsItemField(pw, item, dumpState.getField())); } else { items.forEach(item -> dumpSettingsItem(pw, item)); } } final int n = mItems.size(); for (int i = 0; i < n; i++) { final SettingsItem item = mItems.get(i); private void dumpSettingsItem(@NonNull final IndentingPrintWriter pw, @NonNull final SettingsItem item) { pw.println(item.mPackageName + ":" + item.getUserId() + " {"); pw.increaseIndent(); Loading @@ -318,6 +327,41 @@ final class OverlayManagerSettings { 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; } } void restore(@NonNull final InputStream is) throws IOException, XmlPullParserException { Loading