New log buffer for debugging WakeLocks

Test: adb shell dumpsys activity service \
        com.android.systemui/.dump.SystemUIAuxiliaryDumpService
Bug: 258690929
Change-Id: I7fd1a109f60bda0a22b9e1ecc529fa78e5e20054
This commit is contained in:
Peter Kalauskas
2023-04-12 12:41:58 -07:00
parent fcea4de7d7
commit 7eda3bbc85
10 changed files with 162 additions and 42 deletions

View File

@@ -24,16 +24,13 @@ class BroadcastSender @Inject constructor(
@Background private val bgExecutor: Executor
) {
private val WAKE_LOCK_TAG = "SysUI:BroadcastSender"
private val WAKE_LOCK_SEND_REASON = "sendInBackground"
/**
* Sends broadcast via [Context.sendBroadcast] on background thread to avoid blocking
* synchronous binder call.
*/
@AnyThread
fun sendBroadcast(intent: Intent) {
sendInBackground {
sendInBackground("$intent") {
context.sendBroadcast(intent)
}
}
@@ -44,7 +41,7 @@ class BroadcastSender @Inject constructor(
*/
@AnyThread
fun sendBroadcast(intent: Intent, receiverPermission: String?) {
sendInBackground {
sendInBackground("$intent") {
context.sendBroadcast(intent, receiverPermission)
}
}
@@ -55,7 +52,7 @@ class BroadcastSender @Inject constructor(
*/
@AnyThread
fun sendBroadcastAsUser(intent: Intent, userHandle: UserHandle) {
sendInBackground {
sendInBackground("$intent") {
context.sendBroadcastAsUser(intent, userHandle)
}
}
@@ -66,7 +63,7 @@ class BroadcastSender @Inject constructor(
*/
@AnyThread
fun sendBroadcastAsUser(intent: Intent, userHandle: UserHandle, receiverPermission: String?) {
sendInBackground {
sendInBackground("$intent") {
context.sendBroadcastAsUser(intent, userHandle, receiverPermission)
}
}
@@ -82,7 +79,7 @@ class BroadcastSender @Inject constructor(
receiverPermission: String?,
options: Bundle?
) {
sendInBackground {
sendInBackground("$intent") {
context.sendBroadcastAsUser(intent, userHandle, receiverPermission, options)
}
}
@@ -98,7 +95,7 @@ class BroadcastSender @Inject constructor(
receiverPermission: String?,
appOp: Int
) {
sendInBackground {
sendInBackground("$intent") {
context.sendBroadcastAsUser(intent, userHandle, receiverPermission, appOp)
}
}
@@ -108,7 +105,7 @@ class BroadcastSender @Inject constructor(
*/
@AnyThread
fun closeSystemDialogs() {
sendInBackground {
sendInBackground("closeSystemDialogs") {
context.closeSystemDialogs()
}
}
@@ -116,17 +113,21 @@ class BroadcastSender @Inject constructor(
/**
* Dispatches parameter on background executor while holding a wakelock.
*/
private fun sendInBackground(callable: () -> Unit) {
private fun sendInBackground(reason: String, callable: () -> Unit) {
val broadcastWakelock = wakeLockBuilder.setTag(WAKE_LOCK_TAG)
.setMaxTimeout(5000)
.build()
broadcastWakelock.acquire(WAKE_LOCK_SEND_REASON)
broadcastWakelock.acquire(reason)
bgExecutor.execute {
try {
callable.invoke()
} finally {
broadcastWakelock.release(WAKE_LOCK_SEND_REASON)
broadcastWakelock.release(reason)
}
}
}
companion object {
private const val WAKE_LOCK_TAG = "SysUI:BroadcastSender"
}
}

View File

@@ -60,6 +60,7 @@ import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.wakelock.SettableWakeLock;
import com.android.systemui.util.wakelock.WakeLock;
import com.android.systemui.util.wakelock.WakeLockLogger;
import java.util.Date;
import java.util.Locale;
@@ -148,6 +149,8 @@ public class KeyguardSliceProvider extends SliceProvider implements
private int mStatusBarState;
private boolean mMediaIsVisible;
private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback;
@Inject
WakeLockLogger mWakeLockLogger;
/**
* Receiver responsible for time ticking and updating the date format.
@@ -305,8 +308,8 @@ public class KeyguardSliceProvider extends SliceProvider implements
@Override
public boolean onCreateSliceProvider() {
mContextAvailableCallback.onContextAvailable(getContext());
mMediaWakeLock = new SettableWakeLock(WakeLock.createPartial(getContext(), "media"),
"media");
mMediaWakeLock = new SettableWakeLock(
WakeLock.createPartial(getContext(), mWakeLockLogger, "media"), "media");
synchronized (KeyguardSliceProvider.sInstanceLock) {
KeyguardSliceProvider oldInstance = KeyguardSliceProvider.sInstance;
if (oldInstance != null) {

View File

@@ -31,6 +31,7 @@ import com.android.systemui.plugins.log.LogcatEchoTrackerDebug;
import com.android.systemui.plugins.log.LogcatEchoTrackerProd;
import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.util.Compile;
import com.android.systemui.util.wakelock.WakeLockLog;
import dagger.Module;
import dagger.Provides;
@@ -168,6 +169,14 @@ public class LogModule {
false /* systrace */);
}
/** Provides a logging buffer for {@link com.android.systemui.broadcast.BroadcastSender} */
@Provides
@SysUISingleton
@WakeLockLog
public static LogBuffer provideWakeLockLog(LogBufferFactory factory) {
return factory.create("WakeLockLog", 500 /* maxSize */, false /* systrace */);
}
/** Provides a logging buffer for all logs related to Toasts shown by SystemUI. */
@Provides
@SysUISingleton

View File

@@ -62,6 +62,7 @@ public class DelayedWakeLock implements WakeLock {
*/
public static class Builder {
private final Context mContext;
private final WakeLockLogger mLogger;
private String mTag;
private Handler mHandler;
@@ -69,8 +70,9 @@ public class DelayedWakeLock implements WakeLock {
* Constructor for DelayedWakeLock.Builder
*/
@Inject
public Builder(Context context) {
public Builder(Context context, WakeLockLogger logger) {
mContext = context;
mLogger = logger;
}
/**
@@ -95,7 +97,7 @@ public class DelayedWakeLock implements WakeLock {
* Build the DelayedWakeLock.
*/
public DelayedWakeLock build() {
return new DelayedWakeLock(mHandler, WakeLock.createPartial(mContext, mTag));
return new DelayedWakeLock(mHandler, WakeLock.createPartial(mContext, mLogger, mTag));
}
}
}

View File

@@ -33,7 +33,7 @@ public class KeepAwakeAnimationListener extends AnimatorListenerAdapter
public KeepAwakeAnimationListener(Context context) {
Assert.isMainThread();
if (sWakeLock == null) {
sWakeLock = WakeLock.createPartial(context, "animation");
sWakeLock = WakeLock.createPartial(context, null, "animation");
}
}

View File

@@ -29,8 +29,8 @@ import javax.inject.Inject;
/** WakeLock wrapper for testability */
public interface WakeLock {
static final String TAG = "WakeLock";
static final String REASON_WRAP = "wrap";
String TAG = "WakeLock";
String REASON_WRAP = "wrap";
/**
* Default wake-lock timeout in milliseconds, to avoid battery regressions.
@@ -57,22 +57,32 @@ public interface WakeLock {
/** @see android.os.PowerManager.WakeLock#wrap(Runnable) */
Runnable wrap(Runnable r);
static WakeLock createPartial(Context context, String tag) {
return createPartial(context, tag, DEFAULT_MAX_TIMEOUT);
}
/**
* Creates a {@link WakeLock} that has a default release timeout.
* @see android.os.PowerManager.WakeLock#acquire(long) */
static WakeLock createPartial(Context context, String tag, long maxTimeout) {
return wrap(createWakeLockInner(context, tag, DEFAULT_LEVELS_AND_FLAGS), maxTimeout);
}
/**
* Creates a {@link WakeLock} that has a default release timeout and flags.
* @see android.os.PowerManager.WakeLock#acquire(long)
*/
static WakeLock createWakeLock(Context context, String tag, int flags, long maxTimeout) {
return wrap(createWakeLockInner(context, tag, flags), maxTimeout);
static WakeLock createPartial(Context context, WakeLockLogger logger, String tag) {
return createPartial(context, logger, tag, DEFAULT_MAX_TIMEOUT);
}
/**
* Creates a {@link WakeLock} that has default flags.
* @see android.os.PowerManager.WakeLock#acquire(long)
*/
static WakeLock createPartial(
Context context, WakeLockLogger logger, String tag, long maxTimeout) {
return wrap(
createWakeLockInner(context, tag, DEFAULT_LEVELS_AND_FLAGS), logger, maxTimeout);
}
/**
* Creates a {@link WakeLock}.
* @see android.os.PowerManager.WakeLock#acquire(long)
*/
static WakeLock createWakeLock(
Context context, WakeLockLogger logger, String tag, int flags, long maxTimeout) {
return wrap(
createWakeLockInner(context, tag, flags), logger, maxTimeout);
}
@VisibleForTesting
@@ -100,14 +110,19 @@ public interface WakeLock {
* @return The new wake lock.
*/
@VisibleForTesting
static WakeLock wrap(final PowerManager.WakeLock inner, long maxTimeout) {
static WakeLock wrap(
final PowerManager.WakeLock inner, WakeLockLogger logger, long maxTimeout) {
return new WakeLock() {
private final HashMap<String, Integer> mActiveClients = new HashMap<>();
/** @see PowerManager.WakeLock#acquire() */
public void acquire(String why) {
mActiveClients.putIfAbsent(why, 0);
mActiveClients.put(why, mActiveClients.get(why) + 1);
int count = mActiveClients.get(why) + 1;
mActiveClients.put(why, count);
if (logger != null) {
logger.logAcquire(inner, why, count);
}
inner.acquire(maxTimeout);
}
@@ -118,10 +133,15 @@ public interface WakeLock {
Log.wtf(TAG, "Releasing WakeLock with invalid reason: " + why,
new Throwable());
return;
} else if (count == 1) {
}
count--;
if (count == 0) {
mActiveClients.remove(why);
} else {
mActiveClients.put(why, count - 1);
mActiveClients.put(why, count);
}
if (logger != null) {
logger.logRelease(inner, why, count);
}
inner.release();
}
@@ -133,7 +153,7 @@ public interface WakeLock {
@Override
public String toString() {
return "active clients= " + mActiveClients.toString();
return "active clients= " + mActiveClients;
}
};
}
@@ -143,13 +163,15 @@ public interface WakeLock {
*/
class Builder {
private final Context mContext;
private final WakeLockLogger mLogger;
private String mTag;
private int mLevelsAndFlags = DEFAULT_LEVELS_AND_FLAGS;
private long mMaxTimeout = DEFAULT_MAX_TIMEOUT;
@Inject
public Builder(Context context) {
public Builder(Context context, WakeLockLogger logger) {
mContext = context;
mLogger = logger;
}
public Builder setTag(String tag) {
@@ -168,7 +190,7 @@ public interface WakeLock {
}
public WakeLock build() {
return WakeLock.createWakeLock(mContext, mTag, mLevelsAndFlags, mMaxTimeout);
return WakeLock.createWakeLock(mContext, mLogger, mTag, mLevelsAndFlags, mMaxTimeout);
}
}
}

View File

@@ -0,0 +1,33 @@
/*
* 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 com.android.systemui.util.wakelock;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.android.systemui.plugins.log.LogBuffer;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import javax.inject.Qualifier;
/** A {@link LogBuffer} for BroadcastSender-related messages. */
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface WakeLockLog {
}

View File

@@ -0,0 +1,50 @@
/*
* 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 com.android.systemui.util.wakelock
import android.os.PowerManager
import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
class WakeLockLogger @Inject constructor(@WakeLockLog private val buffer: LogBuffer) {
fun logAcquire(wakeLock: PowerManager.WakeLock, reason: String, count: Int) {
buffer.log(
WakeLock.TAG,
LogLevel.DEBUG,
{
str1 = wakeLock.tag
str2 = reason
int1 = count
},
{ "Acquire tag=$str1 reason=$str2 count=$int1" }
)
}
fun logRelease(wakeLock: PowerManager.WakeLock, reason: String, count: Int) {
buffer.log(
WakeLock.TAG,
LogLevel.DEBUG,
{
str1 = wakeLock.tag
str2 = reason
int1 = count
},
{ "Release tag=$str1 reason=$str2 count=$int1" }
)
}
}

View File

@@ -45,7 +45,7 @@ public class WakeLockTest extends SysuiTestCase {
mInner = WakeLock.createWakeLockInner(mContext,
WakeLockTest.class.getName(),
PowerManager.PARTIAL_WAKE_LOCK);
mWakeLock = WakeLock.wrap(mInner, 20000);
mWakeLock = WakeLock.wrap(mInner, null, 20000);
}
@After

View File

@@ -55,7 +55,7 @@ public class WakeLockFake implements WakeLock {
private WakeLock mWakeLock;
public Builder(Context context) {
super(context);
super(context, null);
}
public void setWakeLock(WakeLock wakeLock) {