Merge "New log buffer for debugging WakeLocks" into udc-dev

This commit is contained in:
Peter Kalauskas
2023-04-13 21:48:01 +00:00
committed by Android (Google) Code Review
10 changed files with 162 additions and 42 deletions

View File

@@ -24,16 +24,13 @@ class BroadcastSender @Inject constructor(
@Background private val bgExecutor: Executor @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 * Sends broadcast via [Context.sendBroadcast] on background thread to avoid blocking
* synchronous binder call. * synchronous binder call.
*/ */
@AnyThread @AnyThread
fun sendBroadcast(intent: Intent) { fun sendBroadcast(intent: Intent) {
sendInBackground { sendInBackground("$intent") {
context.sendBroadcast(intent) context.sendBroadcast(intent)
} }
} }
@@ -44,7 +41,7 @@ class BroadcastSender @Inject constructor(
*/ */
@AnyThread @AnyThread
fun sendBroadcast(intent: Intent, receiverPermission: String?) { fun sendBroadcast(intent: Intent, receiverPermission: String?) {
sendInBackground { sendInBackground("$intent") {
context.sendBroadcast(intent, receiverPermission) context.sendBroadcast(intent, receiverPermission)
} }
} }
@@ -55,7 +52,7 @@ class BroadcastSender @Inject constructor(
*/ */
@AnyThread @AnyThread
fun sendBroadcastAsUser(intent: Intent, userHandle: UserHandle) { fun sendBroadcastAsUser(intent: Intent, userHandle: UserHandle) {
sendInBackground { sendInBackground("$intent") {
context.sendBroadcastAsUser(intent, userHandle) context.sendBroadcastAsUser(intent, userHandle)
} }
} }
@@ -66,7 +63,7 @@ class BroadcastSender @Inject constructor(
*/ */
@AnyThread @AnyThread
fun sendBroadcastAsUser(intent: Intent, userHandle: UserHandle, receiverPermission: String?) { fun sendBroadcastAsUser(intent: Intent, userHandle: UserHandle, receiverPermission: String?) {
sendInBackground { sendInBackground("$intent") {
context.sendBroadcastAsUser(intent, userHandle, receiverPermission) context.sendBroadcastAsUser(intent, userHandle, receiverPermission)
} }
} }
@@ -82,7 +79,7 @@ class BroadcastSender @Inject constructor(
receiverPermission: String?, receiverPermission: String?,
options: Bundle? options: Bundle?
) { ) {
sendInBackground { sendInBackground("$intent") {
context.sendBroadcastAsUser(intent, userHandle, receiverPermission, options) context.sendBroadcastAsUser(intent, userHandle, receiverPermission, options)
} }
} }
@@ -98,7 +95,7 @@ class BroadcastSender @Inject constructor(
receiverPermission: String?, receiverPermission: String?,
appOp: Int appOp: Int
) { ) {
sendInBackground { sendInBackground("$intent") {
context.sendBroadcastAsUser(intent, userHandle, receiverPermission, appOp) context.sendBroadcastAsUser(intent, userHandle, receiverPermission, appOp)
} }
} }
@@ -108,7 +105,7 @@ class BroadcastSender @Inject constructor(
*/ */
@AnyThread @AnyThread
fun closeSystemDialogs() { fun closeSystemDialogs() {
sendInBackground { sendInBackground("closeSystemDialogs") {
context.closeSystemDialogs() context.closeSystemDialogs()
} }
} }
@@ -116,17 +113,21 @@ class BroadcastSender @Inject constructor(
/** /**
* Dispatches parameter on background executor while holding a wakelock. * 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) val broadcastWakelock = wakeLockBuilder.setTag(WAKE_LOCK_TAG)
.setMaxTimeout(5000) .setMaxTimeout(5000)
.build() .build()
broadcastWakelock.acquire(WAKE_LOCK_SEND_REASON) broadcastWakelock.acquire(reason)
bgExecutor.execute { bgExecutor.execute {
try { try {
callable.invoke() callable.invoke()
} finally { } 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.statusbar.policy.ZenModeController;
import com.android.systemui.util.wakelock.SettableWakeLock; import com.android.systemui.util.wakelock.SettableWakeLock;
import com.android.systemui.util.wakelock.WakeLock; import com.android.systemui.util.wakelock.WakeLock;
import com.android.systemui.util.wakelock.WakeLockLogger;
import java.util.Date; import java.util.Date;
import java.util.Locale; import java.util.Locale;
@@ -148,6 +149,8 @@ public class KeyguardSliceProvider extends SliceProvider implements
private int mStatusBarState; private int mStatusBarState;
private boolean mMediaIsVisible; private boolean mMediaIsVisible;
private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback; private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback;
@Inject
WakeLockLogger mWakeLockLogger;
/** /**
* Receiver responsible for time ticking and updating the date format. * Receiver responsible for time ticking and updating the date format.
@@ -305,8 +308,8 @@ public class KeyguardSliceProvider extends SliceProvider implements
@Override @Override
public boolean onCreateSliceProvider() { public boolean onCreateSliceProvider() {
mContextAvailableCallback.onContextAvailable(getContext()); mContextAvailableCallback.onContextAvailable(getContext());
mMediaWakeLock = new SettableWakeLock(WakeLock.createPartial(getContext(), "media"), mMediaWakeLock = new SettableWakeLock(
"media"); WakeLock.createPartial(getContext(), mWakeLockLogger, "media"), "media");
synchronized (KeyguardSliceProvider.sInstanceLock) { synchronized (KeyguardSliceProvider.sInstanceLock) {
KeyguardSliceProvider oldInstance = KeyguardSliceProvider.sInstance; KeyguardSliceProvider oldInstance = KeyguardSliceProvider.sInstance;
if (oldInstance != null) { 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.plugins.log.LogcatEchoTrackerProd;
import com.android.systemui.statusbar.notification.NotifPipelineFlags; import com.android.systemui.statusbar.notification.NotifPipelineFlags;
import com.android.systemui.util.Compile; import com.android.systemui.util.Compile;
import com.android.systemui.util.wakelock.WakeLockLog;
import dagger.Module; import dagger.Module;
import dagger.Provides; import dagger.Provides;
@@ -168,6 +169,14 @@ public class LogModule {
false /* systrace */); 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 a logging buffer for all logs related to Toasts shown by SystemUI. */
@Provides @Provides
@SysUISingleton @SysUISingleton

View File

@@ -62,6 +62,7 @@ public class DelayedWakeLock implements WakeLock {
*/ */
public static class Builder { public static class Builder {
private final Context mContext; private final Context mContext;
private final WakeLockLogger mLogger;
private String mTag; private String mTag;
private Handler mHandler; private Handler mHandler;
@@ -69,8 +70,9 @@ public class DelayedWakeLock implements WakeLock {
* Constructor for DelayedWakeLock.Builder * Constructor for DelayedWakeLock.Builder
*/ */
@Inject @Inject
public Builder(Context context) { public Builder(Context context, WakeLockLogger logger) {
mContext = context; mContext = context;
mLogger = logger;
} }
/** /**
@@ -95,7 +97,7 @@ public class DelayedWakeLock implements WakeLock {
* Build the DelayedWakeLock. * Build the DelayedWakeLock.
*/ */
public DelayedWakeLock build() { 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) { public KeepAwakeAnimationListener(Context context) {
Assert.isMainThread(); Assert.isMainThread();
if (sWakeLock == null) { 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 */ /** WakeLock wrapper for testability */
public interface WakeLock { public interface WakeLock {
static final String TAG = "WakeLock"; String TAG = "WakeLock";
static final String REASON_WRAP = "wrap"; String REASON_WRAP = "wrap";
/** /**
* Default wake-lock timeout in milliseconds, to avoid battery regressions. * Default wake-lock timeout in milliseconds, to avoid battery regressions.
@@ -57,22 +57,32 @@ public interface WakeLock {
/** @see android.os.PowerManager.WakeLock#wrap(Runnable) */ /** @see android.os.PowerManager.WakeLock#wrap(Runnable) */
Runnable wrap(Runnable r); 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. * 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) { static WakeLock createPartial(Context context, WakeLockLogger logger, String tag) {
return wrap(createWakeLockInner(context, tag, flags), maxTimeout); 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 @VisibleForTesting
@@ -100,14 +110,19 @@ public interface WakeLock {
* @return The new wake lock. * @return The new wake lock.
*/ */
@VisibleForTesting @VisibleForTesting
static WakeLock wrap(final PowerManager.WakeLock inner, long maxTimeout) { static WakeLock wrap(
final PowerManager.WakeLock inner, WakeLockLogger logger, long maxTimeout) {
return new WakeLock() { return new WakeLock() {
private final HashMap<String, Integer> mActiveClients = new HashMap<>(); private final HashMap<String, Integer> mActiveClients = new HashMap<>();
/** @see PowerManager.WakeLock#acquire() */ /** @see PowerManager.WakeLock#acquire() */
public void acquire(String why) { public void acquire(String why) {
mActiveClients.putIfAbsent(why, 0); 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); inner.acquire(maxTimeout);
} }
@@ -118,10 +133,15 @@ public interface WakeLock {
Log.wtf(TAG, "Releasing WakeLock with invalid reason: " + why, Log.wtf(TAG, "Releasing WakeLock with invalid reason: " + why,
new Throwable()); new Throwable());
return; return;
} else if (count == 1) { }
count--;
if (count == 0) {
mActiveClients.remove(why); mActiveClients.remove(why);
} else { } else {
mActiveClients.put(why, count - 1); mActiveClients.put(why, count);
}
if (logger != null) {
logger.logRelease(inner, why, count);
} }
inner.release(); inner.release();
} }
@@ -133,7 +153,7 @@ public interface WakeLock {
@Override @Override
public String toString() { public String toString() {
return "active clients= " + mActiveClients.toString(); return "active clients= " + mActiveClients;
} }
}; };
} }
@@ -143,13 +163,15 @@ public interface WakeLock {
*/ */
class Builder { class Builder {
private final Context mContext; private final Context mContext;
private final WakeLockLogger mLogger;
private String mTag; private String mTag;
private int mLevelsAndFlags = DEFAULT_LEVELS_AND_FLAGS; private int mLevelsAndFlags = DEFAULT_LEVELS_AND_FLAGS;
private long mMaxTimeout = DEFAULT_MAX_TIMEOUT; private long mMaxTimeout = DEFAULT_MAX_TIMEOUT;
@Inject @Inject
public Builder(Context context) { public Builder(Context context, WakeLockLogger logger) {
mContext = context; mContext = context;
mLogger = logger;
} }
public Builder setTag(String tag) { public Builder setTag(String tag) {
@@ -168,7 +190,7 @@ public interface WakeLock {
} }
public WakeLock build() { 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, mInner = WakeLock.createWakeLockInner(mContext,
WakeLockTest.class.getName(), WakeLockTest.class.getName(),
PowerManager.PARTIAL_WAKE_LOCK); PowerManager.PARTIAL_WAKE_LOCK);
mWakeLock = WakeLock.wrap(mInner, 20000); mWakeLock = WakeLock.wrap(mInner, null, 20000);
} }
@After @After

View File

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