1 /*
2  * Copyright (C) 2024 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.server.display.mode;
18 
19 import static com.android.internal.util.FrameworkStatsLog.DISPLAY_MODE_DIRECTOR_VOTE_CHANGED;
20 import static com.android.internal.util.FrameworkStatsLog.DISPLAY_MODE_DIRECTOR_VOTE_CHANGED__VOTE_STATUS__STATUS_ACTIVE;
21 import static com.android.internal.util.FrameworkStatsLog.DISPLAY_MODE_DIRECTOR_VOTE_CHANGED__VOTE_STATUS__STATUS_ADDED;
22 import static com.android.internal.util.FrameworkStatsLog.DISPLAY_MODE_DIRECTOR_VOTE_CHANGED__VOTE_STATUS__STATUS_REMOVED;
23 
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.os.Trace;
27 import android.util.SparseArray;
28 import android.view.Display;
29 
30 import com.android.internal.util.FrameworkStatsLog;
31 
32 /**
33  * The VotesStatsReporter is responsible for collecting and sending Vote related statistics
34  */
35 class VotesStatsReporter {
36     private static final String TAG = "VotesStatsReporter";
37     private static final int REFRESH_RATE_NOT_LIMITED = 1000;
38     private final boolean mIgnoredRenderRate;
39     private final boolean mFrameworkStatsLogReportingEnabled;
40 
41     private int mLastMinPriorityReported = Vote.MAX_PRIORITY + 1;
42 
VotesStatsReporter(boolean ignoreRenderRate, boolean refreshRateVotingTelemetryEnabled)43     public VotesStatsReporter(boolean ignoreRenderRate, boolean refreshRateVotingTelemetryEnabled) {
44         mIgnoredRenderRate = ignoreRenderRate;
45         mFrameworkStatsLogReportingEnabled = refreshRateVotingTelemetryEnabled;
46     }
47 
reportVoteChanged(int displayId, int priority, @Nullable Vote vote)48     void reportVoteChanged(int displayId, int priority,  @Nullable Vote vote) {
49         if (vote == null) {
50             reportVoteRemoved(displayId, priority);
51         } else {
52             reportVoteAdded(displayId, priority, vote);
53         }
54     }
55 
reportVoteAdded(int displayId, int priority, @NonNull Vote vote)56     private void reportVoteAdded(int displayId, int priority,  @NonNull Vote vote) {
57         int maxRefreshRate = getMaxRefreshRate(vote, mIgnoredRenderRate);
58         Trace.traceCounter(Trace.TRACE_TAG_POWER,
59                 TAG + "." + displayId + ":" + Vote.priorityToString(priority), maxRefreshRate);
60         if (mFrameworkStatsLogReportingEnabled) {
61             FrameworkStatsLog.write(
62                     DISPLAY_MODE_DIRECTOR_VOTE_CHANGED, displayId, priority,
63                     DISPLAY_MODE_DIRECTOR_VOTE_CHANGED__VOTE_STATUS__STATUS_ADDED,
64                     maxRefreshRate, -1);
65         }
66     }
67 
reportVoteRemoved(int displayId, int priority)68     private void reportVoteRemoved(int displayId, int priority) {
69         Trace.traceCounter(Trace.TRACE_TAG_POWER,
70                 TAG + "." + displayId + ":" + Vote.priorityToString(priority), -1);
71         if (mFrameworkStatsLogReportingEnabled) {
72             FrameworkStatsLog.write(
73                     DISPLAY_MODE_DIRECTOR_VOTE_CHANGED, displayId, priority,
74                     DISPLAY_MODE_DIRECTOR_VOTE_CHANGED__VOTE_STATUS__STATUS_REMOVED, -1, -1);
75         }
76     }
77 
reportVotesActivated(int displayId, int minPriority, @Nullable Display.Mode baseMode, SparseArray<Vote> votes)78     void reportVotesActivated(int displayId, int minPriority, @Nullable Display.Mode baseMode,
79             SparseArray<Vote> votes) {
80         if (!mFrameworkStatsLogReportingEnabled) {
81             return;
82         }
83         int selectedRefreshRate = baseMode != null ? (int) baseMode.getRefreshRate() : -1;
84         for (int priority = Vote.MIN_PRIORITY; priority <= Vote.MAX_PRIORITY; priority++) {
85             if (priority < mLastMinPriorityReported && priority < minPriority) {
86                 continue;
87             }
88             Vote vote = votes.get(priority);
89             if (vote == null) {
90                 continue;
91             }
92 
93             // Was previously reported ACTIVE, changed to ADDED
94             if (priority >= mLastMinPriorityReported && priority < minPriority) {
95                 int maxRefreshRate = getMaxRefreshRate(vote, mIgnoredRenderRate);
96                 FrameworkStatsLog.write(
97                         DISPLAY_MODE_DIRECTOR_VOTE_CHANGED, displayId, priority,
98                         DISPLAY_MODE_DIRECTOR_VOTE_CHANGED__VOTE_STATUS__STATUS_ADDED,
99                         maxRefreshRate, selectedRefreshRate);
100             }
101             // Was previously reported ADDED, changed to ACTIVE
102             if (priority >= minPriority && priority < mLastMinPriorityReported) {
103                 int maxRefreshRate = getMaxRefreshRate(vote, mIgnoredRenderRate);
104                 FrameworkStatsLog.write(
105                         DISPLAY_MODE_DIRECTOR_VOTE_CHANGED, displayId, priority,
106                         DISPLAY_MODE_DIRECTOR_VOTE_CHANGED__VOTE_STATUS__STATUS_ACTIVE,
107                         maxRefreshRate, selectedRefreshRate);
108             }
109 
110             mLastMinPriorityReported = minPriority;
111         }
112     }
113 
getMaxRefreshRate(@onNull Vote vote, boolean ignoreRenderRate)114     private static int getMaxRefreshRate(@NonNull Vote vote, boolean ignoreRenderRate) {
115         int maxRefreshRate = REFRESH_RATE_NOT_LIMITED;
116         if (vote instanceof RefreshRateVote.PhysicalVote physicalVote) {
117             maxRefreshRate = (int) physicalVote.mMaxRefreshRate;
118         } else if (!ignoreRenderRate && (vote instanceof RefreshRateVote.RenderVote renderVote)) {
119             maxRefreshRate = (int)  renderVote.mMaxRefreshRate;
120         } else if (vote instanceof SupportedRefreshRatesVote refreshRatesVote) {
121             // SupportedRefreshRatesVote limits mode by refreshRates, so highest rr is allowed
122             maxRefreshRate = 0;
123             for (SupportedRefreshRatesVote.RefreshRates rr : refreshRatesVote.mRefreshRates) {
124                 maxRefreshRate = Math.max(maxRefreshRate, (int) rr.mPeakRefreshRate);
125             }
126         } else if (vote instanceof CombinedVote combinedVote) {
127             for (Vote subVote: combinedVote.mVotes) {
128                 // CombinedVote should not have CombinedVote in mVotes, so recursion depth will be 1
129                 maxRefreshRate = Math.min(maxRefreshRate,
130                         getMaxRefreshRate(subVote, ignoreRenderRate));
131             }
132         }
133         return maxRefreshRate;
134     }
135 }
136