Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5464aa5d authored by Caitlin Shkuratov's avatar Caitlin Shkuratov
Browse files

[SB][Screen Chips] Convert CastController logs to LogBuffer.

The new screen chips rely on some data from CastController, and it would
be great to always have that log information available in a LogBuffer.

Bug: 351785188
Bug: 332662551
Flag: NONE logging change

Test: Do some cast interactions then dump `CastControllerLog` -> verify
logging
Test: atest CastControllerImplTest

Change-Id: Iab36b4df3399ab6260213d5733fdb517f0b0e4f0
parent 0ff31a6d
Loading
Loading
Loading
Loading
+22 −31
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
import android.os.Handler;
import android.util.ArrayMap;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -46,11 +45,11 @@ import javax.inject.Inject;
/** Platform implementation of the cast controller. **/
@SysUISingleton
public class CastControllerImpl implements CastController {
    public static final String TAG = "CastController";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
    private static final String TAG = "CastController";

    private final Context mContext;
    private final PackageManager mPackageManager;
    private final CastControllerLogger mLogger;
    @GuardedBy("mCallbacks")
    private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
    private final MediaRouter mMediaRouter;
@@ -67,20 +66,22 @@ public class CastControllerImpl implements CastController {
    public CastControllerImpl(
            Context context,
            PackageManager packageManager,
            DumpManager dumpManager) {
            DumpManager dumpManager,
            CastControllerLogger logger) {
        mContext = context;
        mPackageManager = packageManager;
        mLogger = logger;
        mMediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
        mMediaRouter.setRouterGroupId(MediaRouter.MIRRORING_GROUP_ID);
        mProjectionManager = (MediaProjectionManager)
                context.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
        mProjection = mProjectionManager.getActiveProjectionInfo();
        mProjectionManager.addCallback(mProjectionCallback, new Handler());
        dumpManager.registerDumpable(TAG, this);
        if (DEBUG) Log.d(TAG, "new CastController()");
        dumpManager.registerNormalDumpable(TAG, this);
    }

    public void dump(PrintWriter pw, String[] args) {
    @Override
    public void dump(PrintWriter pw, @NonNull String[] args) {
        pw.println("CastController state:");
        pw.print("  mDiscovering="); pw.println(mDiscovering);
        pw.print("  mCallbackRegistered="); pw.println(mCallbackRegistered);
@@ -88,7 +89,7 @@ public class CastControllerImpl implements CastController {
        pw.print("  mRoutes.size="); pw.println(mRoutes.size());
        for (int i = 0; i < mRoutes.size(); i++) {
            final RouteInfo route = mRoutes.valueAt(i);
            pw.print("    "); pw.println(routeToString(route));
            pw.print("    "); pw.println(CastControllerLogger.Companion.toLogString(route));
        }
        pw.print("  mProjection="); pw.println(mProjection);
    }
@@ -119,7 +120,7 @@ public class CastControllerImpl implements CastController {
        synchronized (mDiscoveringLock) {
            if (mDiscovering == request) return;
            mDiscovering = request;
            if (DEBUG) Log.d(TAG, "setDiscovering: " + request);
            mLogger.logDiscovering(request);
            handleDiscoveryChangeLocked();
        }
    }
@@ -166,7 +167,8 @@ public class CastControllerImpl implements CastController {
                        CastDevice.Companion.toCastDevice(
                                mProjection,
                                mContext,
                                mPackageManager));
                                mPackageManager,
                                mLogger));
            }
        }

@@ -177,7 +179,7 @@ public class CastControllerImpl implements CastController {
    public void startCasting(CastDevice device) {
        if (device == null || device.getTag() == null) return;
        final RouteInfo route = (RouteInfo) device.getTag();
        if (DEBUG) Log.d(TAG, "startCasting: " + routeToString(route));
        mLogger.logStartCasting(route);
        mMediaRouter.selectRoute(ROUTE_TYPE_REMOTE_DISPLAY, route);
    }

@@ -185,15 +187,16 @@ public class CastControllerImpl implements CastController {
    public void stopCasting(CastDevice device) {
        // TODO(b/332662551): Convert Logcat to LogBuffer.
        final boolean isProjection = device.getTag() instanceof MediaProjectionInfo;
        if (DEBUG) Log.d(TAG, "stopCasting isProjection=" + isProjection);
        mLogger.logStopCasting(isProjection);
        if (isProjection) {
            final MediaProjectionInfo projection = (MediaProjectionInfo) device.getTag();
            if (Objects.equals(mProjectionManager.getActiveProjectionInfo(), projection)) {
                mProjectionManager.stopActiveProjection();
            } else {
                Log.w(TAG, "Projection is no longer active: " + projection);
                mLogger.logStopCastingNoProjection(projection);
            }
        } else {
            mLogger.logStopCastingMediaRouter();
            mMediaRouter.getFallbackRoute().select();
        }
    }
@@ -218,7 +221,7 @@ public class CastControllerImpl implements CastController {
            }
        }
        if (changed) {
            if (DEBUG) Log.d(TAG, "setProjection: " + oldProjection + " -> " + mProjection);
            mLogger.logSetProjection(oldProjection, mProjection);
            fireOnCastDevicesChanged();
        }
    }
@@ -265,42 +268,30 @@ public class CastControllerImpl implements CastController {
        callback.onCastDevicesChanged();
    }

    private static String routeToString(RouteInfo route) {
        if (route == null) return null;
        final StringBuilder sb = new StringBuilder().append(route.getName()).append('/')
                .append(route.getDescription()).append('@').append(route.getDeviceAddress())
                .append(",status=").append(route.getStatus());
        if (route.isDefault()) sb.append(",default");
        if (route.isEnabled()) sb.append(",enabled");
        if (route.isConnecting()) sb.append(",connecting");
        if (route.isSelected()) sb.append(",selected");
        return sb.append(",id=").append(route.getTag()).toString();
    }

    private final MediaRouter.SimpleCallback mMediaCallback = new MediaRouter.SimpleCallback() {
        @Override
        public void onRouteAdded(MediaRouter router, RouteInfo route) {
            if (DEBUG) Log.d(TAG, "onRouteAdded: " + routeToString(route));
            mLogger.logRouteAdded(route);
            updateRemoteDisplays();
        }
        @Override
        public void onRouteChanged(MediaRouter router, RouteInfo route) {
            if (DEBUG) Log.d(TAG, "onRouteChanged: " + routeToString(route));
            mLogger.logRouteChanged(route);
            updateRemoteDisplays();
        }
        @Override
        public void onRouteRemoved(MediaRouter router, RouteInfo route) {
            if (DEBUG) Log.d(TAG, "onRouteRemoved: " + routeToString(route));
            mLogger.logRouteRemoved(route);
            updateRemoteDisplays();
        }
        @Override
        public void onRouteSelected(MediaRouter router, int type, RouteInfo route) {
            if (DEBUG) Log.d(TAG, "onRouteSelected(" + type + "): " + routeToString(route));
            mLogger.logRouteSelected(route, type);
            updateRemoteDisplays();
        }
        @Override
        public void onRouteUnselected(MediaRouter router, int type, RouteInfo route) {
            if (DEBUG) Log.d(TAG, "onRouteUnselected(" + type + "): " + routeToString(route));
            mLogger.logRouteUnselected(route, type);
            updateRemoteDisplays();
        }
    };
+141 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.statusbar.policy

import android.media.MediaRouter.RouteInfo
import android.media.projection.MediaProjectionInfo
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.core.MessageInitializer
import com.android.systemui.log.core.MessagePrinter
import com.android.systemui.statusbar.policy.dagger.CastControllerLog
import javax.inject.Inject

/** Helper class for logging events to [CastControllerLog] from Java. */
@SysUISingleton
class CastControllerLogger
@Inject
constructor(
    @CastControllerLog val logger: LogBuffer,
) {
    /** Passthrough to [logger]. */
    inline fun log(
        tag: String,
        level: LogLevel,
        messageInitializer: MessageInitializer,
        noinline messagePrinter: MessagePrinter,
        exception: Throwable? = null,
    ) {
        logger.log(tag, level, messageInitializer, messagePrinter, exception)
    }

    fun logDiscovering(isDiscovering: Boolean) =
        logger.log(TAG, LogLevel.DEBUG, { bool1 = isDiscovering }, { "setDiscovering: $bool1" })

    fun logStartCasting(route: RouteInfo) =
        logger.log(TAG, LogLevel.DEBUG, { str1 = route.toLogString() }, { "startCasting: $str1" })

    fun logStopCasting(isProjection: Boolean) =
        logger.log(
            TAG,
            LogLevel.DEBUG,
            { bool1 = isProjection },
            { "stopCasting. isProjection=$bool1" },
        )

    fun logStopCastingNoProjection(projection: MediaProjectionInfo) =
        logger.log(
            TAG,
            LogLevel.WARNING,
            { str1 = projection.toString() },
            { "stopCasting failed because projection is no longer active: $str1" },
        )

    fun logStopCastingMediaRouter() =
        logger.log(
            TAG,
            LogLevel.DEBUG,
            {},
            { "stopCasting is selecting fallback route in MediaRouter" },
        )

    fun logSetProjection(oldInfo: MediaProjectionInfo?, newInfo: MediaProjectionInfo?) =
        logger.log(
            TAG,
            LogLevel.DEBUG,
            {
                str1 = oldInfo.toString()
                str2 = newInfo.toString()
            },
            { "setProjection: $str1 -> $str2" },
        )

    fun logRouteAdded(route: RouteInfo) =
        logger.log(TAG, LogLevel.DEBUG, { str1 = route.toLogString() }, { "onRouteAdded: $str1" })

    fun logRouteChanged(route: RouteInfo) =
        logger.log(TAG, LogLevel.DEBUG, { str1 = route.toLogString() }, { "onRouteChanged: $str1" })

    fun logRouteRemoved(route: RouteInfo) =
        logger.log(TAG, LogLevel.DEBUG, { str1 = route.toLogString() }, { "onRouteRemoved: $str1" })

    fun logRouteSelected(route: RouteInfo, type: Int) =
        logger.log(
            TAG,
            LogLevel.DEBUG,
            {
                str1 = route.toLogString()
                int1 = type
            },
            { "onRouteSelected($int1): $str1" },
        )

    fun logRouteUnselected(route: RouteInfo, type: Int) =
        logger.log(
            TAG,
            LogLevel.DEBUG,
            {
                str1 = route.toLogString()
                int1 = type
            },
            { "onRouteUnselected($int1): $str1" },
        )

    companion object {
        @JvmStatic
        fun RouteInfo?.toLogString(): String? {
            if (this == null) return null
            val sb =
                StringBuilder()
                    .append(name)
                    .append('/')
                    .append(description)
                    .append('@')
                    .append(deviceAddress)
                    .append(",status=")
                    .append(status)
            if (isDefault) sb.append(",default")
            if (isEnabled) sb.append(",enabled")
            if (isConnecting) sb.append(",connecting")
            if (isSelected) sb.append(",selected")
            return sb.append(",id=").append(this.tag).toString()
        }

        private const val TAG = "CastController"
    }
}
+22 −6
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ import android.content.pm.PackageManager
import android.media.MediaRouter
import android.media.projection.MediaProjectionInfo
import android.text.TextUtils
import android.util.Log
import com.android.systemui.log.core.LogLevel
import com.android.systemui.res.R
import com.android.systemui.util.Utils

@@ -64,11 +64,12 @@ data class CastDevice(
        /** Creates a [CastDevice] based on the provided information from MediaProjection. */
        fun MediaProjectionInfo.toCastDevice(
            context: Context,
            packageManager: PackageManager
            packageManager: PackageManager,
            logger: CastControllerLogger,
        ): CastDevice {
            return CastDevice(
                id = this.packageName,
                name = getAppName(this.packageName, packageManager),
                name = getAppName(this.packageName, packageManager, logger),
                description = context.getString(R.string.quick_settings_casting),
                state = CastState.Connected,
                tag = this,
@@ -76,7 +77,11 @@ data class CastDevice(
            )
        }

        private fun getAppName(packageName: String, packageManager: PackageManager): String {
        private fun getAppName(
            packageName: String,
            packageManager: PackageManager,
            logger: CastControllerLogger,
        ): String {
            if (Utils.isHeadlessRemoteDisplayProvider(packageManager, packageName)) {
                return ""
            }
@@ -86,9 +91,20 @@ data class CastDevice(
                if (!TextUtils.isEmpty(label)) {
                    return label.toString()
                }
                Log.w(CastControllerImpl.TAG, "No label found for package: $packageName")
                logger.log(
                    "#getAppName",
                    LogLevel.WARNING,
                    { str1 = packageName },
                    { "No label found for package: $str1" },
                )
            } catch (e: PackageManager.NameNotFoundException) {
                Log.w(CastControllerImpl.TAG, "Error getting appName for package: $packageName", e)
                logger.log(
                    "#getAppName",
                    LogLevel.WARNING,
                    { str1 = packageName },
                    { "Error getting appName for package=$str1" },
                    e,
                )
            }
            return packageName
        }
+28 −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 com.android.systemui.statusbar.policy.dagger

import javax.inject.Qualifier

/**
 * Logs for cast events. See [com.android.systemui.statusbar.policy.CastControllerImpl] and
 * [com.android.systemui.statusbar.policy.CastControllerLogger].
 */
@Qualifier
@MustBeDocumented
@Retention(AnnotationRetention.RUNTIME)
annotation class CastControllerLog
+8 −0
Original line number Diff line number Diff line
@@ -228,4 +228,12 @@ public interface StatusBarPolicyModule {
    static LogBuffer provideBatteryControllerLog(LogBufferFactory factory) {
        return factory.create(BatteryControllerLogger.TAG, 30);
    }

    /** Provides a log buffer for CastControllerImpl */
    @Provides
    @SysUISingleton
    @CastControllerLog
    static LogBuffer provideCastControllerLog(LogBufferFactory factory) {
        return factory.create("CastControllerLog", 50);
    }
}
Loading