• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.car.cluster;
18 
19 import static com.android.car.internal.common.CommonConstants.EMPTY_BYTE_ARRAY;
20 
21 import android.car.builtin.util.Slogf;
22 import android.content.Context;
23 import android.content.res.Resources;
24 import android.util.Log;
25 import android.view.SurfaceControl;
26 
27 import com.android.car.CarLog;
28 import com.android.car.R;
29 import com.android.car.hal.ClusterHalService;
30 import com.android.car.internal.util.IndentingPrintWriter;
31 import com.android.internal.annotations.GuardedBy;
32 
33 import java.util.function.Consumer;
34 
35 /**
36  * Provides the functionalities regarding to the health monitoring and the heartbeat.
37  */
38 final class ClusterHealthMonitor {
39     private static final String TAG = CarLog.TAG_CLUSTER;
40     private static final boolean DBG = Slogf.isLoggable(TAG, Log.DEBUG);
41 
42     private final Context mContext;
43     private final ClusterHalService mClusterHalService;
44     private final float mTplThresholdMinAlpha;
45     private final float mTplThresholdMinFractionRendered;
46     private final int mTplThresholdStabilityMs;
47     private final Object mLock = new Object();
48 
49     @GuardedBy("mLock")
50     private SurfaceControl mClusterActivitySurface;
51     @GuardedBy("mLock")
52     private volatile boolean mClusterActivityVisible;
53     @GuardedBy("mLock")
54     private int mTrustedPresentationListenerCount;
55 
ClusterHealthMonitor(Context context, ClusterHalService clusterHalService)56     ClusterHealthMonitor(Context context, ClusterHalService clusterHalService) {
57         mContext = context;
58         mClusterHalService = clusterHalService;
59 
60         Resources resources = mContext.getResources();
61         mTplThresholdMinAlpha = resources.getFraction(
62                 R.fraction.config_clusterHomeVisibility_minAlpha, /* base= */ 1, /* pbase= */ 1);
63         mTplThresholdMinFractionRendered = resources.getFraction(
64                 R.fraction.config_clusterHomeVisibility_minRendered, /* base= */ 1, /* pbase= */ 1);
65         mTplThresholdStabilityMs = resources.getInteger(
66                 R.integer.config_clusterHomeVisibility_stabilityMs);
67     }
68 
dump(IndentingPrintWriter writer)69     void dump(IndentingPrintWriter writer) {
70         writer.println("*ClusterHealthMonitor*");
71         writer.increaseIndent();
72         synchronized (mLock) {
73             writer.printf("mClusterActivitySurface: %s\n", mClusterActivitySurface);
74             writer.printf("mClusterActivityVisible: %b\n", mClusterActivityVisible);
75             writer.printf("mTrustedPresentationListenerCount: %d\n",
76                     mTrustedPresentationListenerCount);
77         }
78         writer.printf("mTplThresholdMinAlpha: %f\n", mTplThresholdMinAlpha);
79         writer.printf("mTplThresholdMinFractionRendered: %f\n", mTplThresholdMinFractionRendered);
80         writer.printf("mTplThresholdStabilityMs: %d\n", mTplThresholdStabilityMs);
81         writer.decreaseIndent();
82     }
83 
sendHeartbeat(long epochTimeNs, byte[] appMetadata)84     void sendHeartbeat(long epochTimeNs, byte[] appMetadata) {
85         if (appMetadata == null) {
86             appMetadata = EMPTY_BYTE_ARRAY;
87         }
88         boolean visible;
89         synchronized (mLock) {
90             visible = mClusterActivityVisible;
91         }
92         sendHeartbeatInternal(epochTimeNs, visible, appMetadata);
93     }
94 
sendHeartbeatInternal(long epochTimeNs, boolean visible, byte[] appMetadata)95     private void sendHeartbeatInternal(long epochTimeNs, boolean visible, byte[] appMetadata) {
96         mClusterHalService.sendHeartbeat(epochTimeNs, visible ? 1 : 0, appMetadata);
97     }
98 
startVisibilityMonitoring(SurfaceControl surface)99     void startVisibilityMonitoring(SurfaceControl surface) {
100         if (DBG) {
101             Slogf.d(TAG, "startVisibilityMonitoring: surface=%s", surface);
102         }
103         synchronized (mLock) {
104             SurfaceControl.Transaction t = new SurfaceControl.Transaction();
105             if (mClusterActivitySurface != null) {
106                 t.clearTrustedPresentationCallback(mClusterActivitySurface);
107             }
108             t.setTrustedPresentationCallback(surface,
109                     new SurfaceControl.TrustedPresentationThresholds(
110                             mTplThresholdMinAlpha, mTplThresholdMinFractionRendered,
111                             mTplThresholdStabilityMs),
112                     mContext.getMainExecutor(), mTrustedPresentationListener);
113             t.apply();
114             mClusterActivitySurface = surface;
115             // The callback is expected to be called right away if the Surface is already visible.
116             mClusterActivityVisible = false;
117         }
118     }
119 
120     private final Consumer<Boolean> mTrustedPresentationListener = inTrustedPresentationState -> {
121         if (DBG) {
122             Slogf.d(TAG, "inTrustedPresentationState=%b", inTrustedPresentationState);
123         }
124         synchronized (mLock) {
125             ++mTrustedPresentationListenerCount;
126             mClusterActivityVisible = inTrustedPresentationState;
127         }
128         sendHeartbeatInternal(System.nanoTime(), inTrustedPresentationState, EMPTY_BYTE_ARRAY);
129     };
130 
stopVisibilityMonitoring()131     void stopVisibilityMonitoring() {
132         if (DBG) {
133             Slogf.d(TAG, "stopVisibilityMonitoring");
134         }
135         synchronized (mLock) {
136             if (mClusterActivitySurface != null) {
137                 SurfaceControl.Transaction t = new SurfaceControl.Transaction();
138                 t.clearTrustedPresentationCallback(mClusterActivitySurface);
139                 t.apply();
140             }
141             mClusterActivitySurface = null;
142             mClusterActivityVisible = false;
143         }
144     }
145 }
146