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:
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -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" }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user