Loading core/java/android/util/TeeWriter.java 0 → 100644 +62 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 android.util; import android.annotation.NonNull; import java.io.IOException; import java.io.Writer; import java.util.Objects; /** * Writer that offers to "tee" identical output to multiple underlying * {@link Writer} instances. * * @see https://man7.org/linux/man-pages/man1/tee.1.html * @hide */ public class TeeWriter extends Writer { private final @NonNull Writer[] mWriters; public TeeWriter(@NonNull Writer... writers) { for (Writer writer : writers) { Objects.requireNonNull(writer); } mWriters = writers; } @Override public void write(char[] cbuf, int off, int len) throws IOException { for (Writer writer : mWriters) { writer.write(cbuf, off, len); } } @Override public void flush() throws IOException { for (Writer writer : mWriters) { writer.flush(); } } @Override public void close() throws IOException { for (Writer writer : mWriters) { writer.close(); } } } services/core/java/com/android/server/am/ActivityManagerDebugConfig.java +9 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,11 @@ package com.android.server.am; import android.util.Log; import android.util.LogWriter; import java.io.PrintWriter; /** * Common class for the various debug {@link android.util.Log} output configuration in the activity * manager package. Loading @@ -38,6 +43,10 @@ class ActivityManagerDebugConfig { // Default log tag for the activity manager package. static final String TAG_AM = "ActivityManager"; // Default writer that emits "info" log events for the activity manager package. static final PrintWriter LOG_WRITER_INFO = new PrintWriter( new LogWriter(Log.INFO, TAG_AM)); // Enable all debug log categories. static final boolean DEBUG_ALL = false; Loading services/core/java/com/android/server/am/ActivityManagerService.java +11 −13 Original line number Diff line number Diff line Loading @@ -135,6 +135,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE; import static com.android.server.am.ActivityManagerDebugConfig.LOG_WRITER_INFO; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP; Loading Loading @@ -18723,27 +18724,25 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void waitForBroadcastIdle() { waitForBroadcastIdle(/* printWriter= */ null); waitForBroadcastIdle(LOG_WRITER_INFO); } public void waitForBroadcastIdle(@Nullable PrintWriter pw) { public void waitForBroadcastIdle(@NonNull PrintWriter pw) { enforceCallingPermission(permission.DUMP, "waitForBroadcastIdle()"); BroadcastLoopers.waitForIdle(pw); for (BroadcastQueue queue : mBroadcastQueues) { queue.waitForIdle(pw); } if (pw != null) { pw.println("All broadcast queues are idle!"); pw.flush(); } } @Override public void waitForBroadcastBarrier() { waitForBroadcastBarrier(/* printWriter= */ null, false, false); waitForBroadcastBarrier(LOG_WRITER_INFO, false, false); } public void waitForBroadcastBarrier(@Nullable PrintWriter pw, public void waitForBroadcastBarrier(@NonNull PrintWriter pw, boolean flushBroadcastLoopers, boolean flushApplicationThreads) { enforceCallingPermission(permission.DUMP, "waitForBroadcastBarrier()"); if (flushBroadcastLoopers) { Loading @@ -18761,11 +18760,7 @@ public class ActivityManagerService extends IActivityManager.Stub * Wait for all pending {@link IApplicationThread} events to be processed in * all currently running apps. */ public void waitForApplicationBarrier(@Nullable PrintWriter pw) { if (pw == null) { pw = new PrintWriter(new LogWriter(Log.VERBOSE, TAG)); } public void waitForApplicationBarrier(@NonNull PrintWriter pw) { final CountDownLatch finishedLatch = new CountDownLatch(1); final AtomicInteger pingCount = new AtomicInteger(0); final AtomicInteger pongCount = new AtomicInteger(0); Loading Loading @@ -18815,15 +18810,18 @@ public class ActivityManagerService extends IActivityManager.Stub try { if (finishedLatch.await(1, TimeUnit.SECONDS)) { pw.println("Finished application barriers!"); pw.flush(); return; } else { pw.println("Waiting for application barriers, at " + pongCount.get() + " of " + pingCount.get() + "..."); pw.flush(); } } catch (InterruptedException ignored) { } } pw.println("Gave up waiting for application barriers!"); pw.flush(); } void setIgnoreDeliveryGroupPolicy(@NonNull String broadcastAction) { services/core/java/com/android/server/am/ActivityManagerShellCommand.java +5 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_CRI import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW; import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE; import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL; import static com.android.server.am.ActivityManagerDebugConfig.LOG_WRITER_INFO; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_COUNT; Loading Loading @@ -112,6 +113,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.DebugUtils; import android.util.DisplayMetrics; import android.util.TeeWriter; import android.util.proto.ProtoOutputStream; import android.view.Display; import android.window.SplashScreen; Loading Loading @@ -3364,11 +3366,13 @@ final class ActivityManagerShellCommand extends ShellCommand { } int runWaitForBroadcastIdle(PrintWriter pw) throws RemoteException { pw = new PrintWriter(new TeeWriter(LOG_WRITER_INFO, pw)); mInternal.waitForBroadcastIdle(pw); return 0; } int runWaitForBroadcastBarrier(PrintWriter pw) throws RemoteException { pw = new PrintWriter(new TeeWriter(LOG_WRITER_INFO, pw)); boolean flushBroadcastLoopers = false; boolean flushApplicationThreads = false; String opt; Loading @@ -3387,6 +3391,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } int runWaitForApplicationBarrier(PrintWriter pw) throws RemoteException { pw = new PrintWriter(new TeeWriter(LOG_WRITER_INFO, pw)); mInternal.waitForApplicationBarrier(pw); return 0; } Loading services/core/java/com/android/server/am/BroadcastLoopers.java +7 −14 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.server.am; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Handler; import android.os.Looper; import android.os.Message; Loading Loading @@ -74,7 +73,7 @@ public class BroadcastLoopers { * defined by {@link MessageQueue#isIdle()}. Note that {@link Message#when} * still in the future are ignored for the purposes of the idle test. */ public static void waitForIdle(@Nullable PrintWriter pw) { public static void waitForIdle(@NonNull PrintWriter pw) { waitForCondition(pw, (looper, latch) -> { final MessageQueue queue = looper.getQueue(); queue.addIdleHandler(() -> { Loading @@ -89,7 +88,7 @@ public class BroadcastLoopers { * Note that {@link Message#when} still in the future are ignored for the purposes * of the idle test. */ public static void waitForBarrier(@Nullable PrintWriter pw) { public static void waitForBarrier(@NonNull PrintWriter pw) { waitForCondition(pw, (looper, latch) -> { (new Handler(looper)).post(() -> { latch.countDown(); Loading @@ -100,7 +99,7 @@ public class BroadcastLoopers { /** * Wait for all registered {@link Looper} instances to meet a certain condition. */ private static void waitForCondition(@Nullable PrintWriter pw, private static void waitForCondition(@NonNull PrintWriter pw, @NonNull BiConsumer<Looper, CountDownLatch> condition) { final CountDownLatch latch; synchronized (sLoopers) { Loading @@ -122,18 +121,12 @@ public class BroadcastLoopers { final long now = SystemClock.uptimeMillis(); if (now >= lastPrint + 1000) { lastPrint = now; logv("Waiting for " + latch.getCount() + " loopers to drain...", pw); pw.println("Waiting for " + latch.getCount() + " loopers to drain..."); pw.flush(); } SystemClock.sleep(100); } logv("Loopers drained!", pw); } private static void logv(@NonNull String msg, @Nullable PrintWriter pw) { Slog.v(TAG, msg); if (pw != null) { pw.println(msg); pw.println("Loopers drained!"); pw.flush(); } } } Loading
core/java/android/util/TeeWriter.java 0 → 100644 +62 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 android.util; import android.annotation.NonNull; import java.io.IOException; import java.io.Writer; import java.util.Objects; /** * Writer that offers to "tee" identical output to multiple underlying * {@link Writer} instances. * * @see https://man7.org/linux/man-pages/man1/tee.1.html * @hide */ public class TeeWriter extends Writer { private final @NonNull Writer[] mWriters; public TeeWriter(@NonNull Writer... writers) { for (Writer writer : writers) { Objects.requireNonNull(writer); } mWriters = writers; } @Override public void write(char[] cbuf, int off, int len) throws IOException { for (Writer writer : mWriters) { writer.write(cbuf, off, len); } } @Override public void flush() throws IOException { for (Writer writer : mWriters) { writer.flush(); } } @Override public void close() throws IOException { for (Writer writer : mWriters) { writer.close(); } } }
services/core/java/com/android/server/am/ActivityManagerDebugConfig.java +9 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,11 @@ package com.android.server.am; import android.util.Log; import android.util.LogWriter; import java.io.PrintWriter; /** * Common class for the various debug {@link android.util.Log} output configuration in the activity * manager package. Loading @@ -38,6 +43,10 @@ class ActivityManagerDebugConfig { // Default log tag for the activity manager package. static final String TAG_AM = "ActivityManager"; // Default writer that emits "info" log events for the activity manager package. static final PrintWriter LOG_WRITER_INFO = new PrintWriter( new LogWriter(Log.INFO, TAG_AM)); // Enable all debug log categories. static final boolean DEBUG_ALL = false; Loading
services/core/java/com/android/server/am/ActivityManagerService.java +11 −13 Original line number Diff line number Diff line Loading @@ -135,6 +135,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE; import static com.android.server.am.ActivityManagerDebugConfig.LOG_WRITER_INFO; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BACKUP; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_BROADCAST; import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP; Loading Loading @@ -18723,27 +18724,25 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void waitForBroadcastIdle() { waitForBroadcastIdle(/* printWriter= */ null); waitForBroadcastIdle(LOG_WRITER_INFO); } public void waitForBroadcastIdle(@Nullable PrintWriter pw) { public void waitForBroadcastIdle(@NonNull PrintWriter pw) { enforceCallingPermission(permission.DUMP, "waitForBroadcastIdle()"); BroadcastLoopers.waitForIdle(pw); for (BroadcastQueue queue : mBroadcastQueues) { queue.waitForIdle(pw); } if (pw != null) { pw.println("All broadcast queues are idle!"); pw.flush(); } } @Override public void waitForBroadcastBarrier() { waitForBroadcastBarrier(/* printWriter= */ null, false, false); waitForBroadcastBarrier(LOG_WRITER_INFO, false, false); } public void waitForBroadcastBarrier(@Nullable PrintWriter pw, public void waitForBroadcastBarrier(@NonNull PrintWriter pw, boolean flushBroadcastLoopers, boolean flushApplicationThreads) { enforceCallingPermission(permission.DUMP, "waitForBroadcastBarrier()"); if (flushBroadcastLoopers) { Loading @@ -18761,11 +18760,7 @@ public class ActivityManagerService extends IActivityManager.Stub * Wait for all pending {@link IApplicationThread} events to be processed in * all currently running apps. */ public void waitForApplicationBarrier(@Nullable PrintWriter pw) { if (pw == null) { pw = new PrintWriter(new LogWriter(Log.VERBOSE, TAG)); } public void waitForApplicationBarrier(@NonNull PrintWriter pw) { final CountDownLatch finishedLatch = new CountDownLatch(1); final AtomicInteger pingCount = new AtomicInteger(0); final AtomicInteger pongCount = new AtomicInteger(0); Loading Loading @@ -18815,15 +18810,18 @@ public class ActivityManagerService extends IActivityManager.Stub try { if (finishedLatch.await(1, TimeUnit.SECONDS)) { pw.println("Finished application barriers!"); pw.flush(); return; } else { pw.println("Waiting for application barriers, at " + pongCount.get() + " of " + pingCount.get() + "..."); pw.flush(); } } catch (InterruptedException ignored) { } } pw.println("Gave up waiting for application barriers!"); pw.flush(); } void setIgnoreDeliveryGroupPolicy(@NonNull String broadcastAction) {
services/core/java/com/android/server/am/ActivityManagerShellCommand.java +5 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_CRI import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_LOW; import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_MODERATE; import static com.android.internal.app.procstats.ProcessStats.ADJ_MEM_FACTOR_NORMAL; import static com.android.server.am.ActivityManagerDebugConfig.LOG_WRITER_INFO; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.AppBatteryTracker.BatteryUsage.BATTERY_USAGE_COUNT; Loading Loading @@ -112,6 +113,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.DebugUtils; import android.util.DisplayMetrics; import android.util.TeeWriter; import android.util.proto.ProtoOutputStream; import android.view.Display; import android.window.SplashScreen; Loading Loading @@ -3364,11 +3366,13 @@ final class ActivityManagerShellCommand extends ShellCommand { } int runWaitForBroadcastIdle(PrintWriter pw) throws RemoteException { pw = new PrintWriter(new TeeWriter(LOG_WRITER_INFO, pw)); mInternal.waitForBroadcastIdle(pw); return 0; } int runWaitForBroadcastBarrier(PrintWriter pw) throws RemoteException { pw = new PrintWriter(new TeeWriter(LOG_WRITER_INFO, pw)); boolean flushBroadcastLoopers = false; boolean flushApplicationThreads = false; String opt; Loading @@ -3387,6 +3391,7 @@ final class ActivityManagerShellCommand extends ShellCommand { } int runWaitForApplicationBarrier(PrintWriter pw) throws RemoteException { pw = new PrintWriter(new TeeWriter(LOG_WRITER_INFO, pw)); mInternal.waitForApplicationBarrier(pw); return 0; } Loading
services/core/java/com/android/server/am/BroadcastLoopers.java +7 −14 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.server.am; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Handler; import android.os.Looper; import android.os.Message; Loading Loading @@ -74,7 +73,7 @@ public class BroadcastLoopers { * defined by {@link MessageQueue#isIdle()}. Note that {@link Message#when} * still in the future are ignored for the purposes of the idle test. */ public static void waitForIdle(@Nullable PrintWriter pw) { public static void waitForIdle(@NonNull PrintWriter pw) { waitForCondition(pw, (looper, latch) -> { final MessageQueue queue = looper.getQueue(); queue.addIdleHandler(() -> { Loading @@ -89,7 +88,7 @@ public class BroadcastLoopers { * Note that {@link Message#when} still in the future are ignored for the purposes * of the idle test. */ public static void waitForBarrier(@Nullable PrintWriter pw) { public static void waitForBarrier(@NonNull PrintWriter pw) { waitForCondition(pw, (looper, latch) -> { (new Handler(looper)).post(() -> { latch.countDown(); Loading @@ -100,7 +99,7 @@ public class BroadcastLoopers { /** * Wait for all registered {@link Looper} instances to meet a certain condition. */ private static void waitForCondition(@Nullable PrintWriter pw, private static void waitForCondition(@NonNull PrintWriter pw, @NonNull BiConsumer<Looper, CountDownLatch> condition) { final CountDownLatch latch; synchronized (sLoopers) { Loading @@ -122,18 +121,12 @@ public class BroadcastLoopers { final long now = SystemClock.uptimeMillis(); if (now >= lastPrint + 1000) { lastPrint = now; logv("Waiting for " + latch.getCount() + " loopers to drain...", pw); pw.println("Waiting for " + latch.getCount() + " loopers to drain..."); pw.flush(); } SystemClock.sleep(100); } logv("Loopers drained!", pw); } private static void logv(@NonNull String msg, @Nullable PrintWriter pw) { Slog.v(TAG, msg); if (pw != null) { pw.println(msg); pw.println("Loopers drained!"); pw.flush(); } } }