• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.wifi.p2p;
18 
19 import static android.os.Process.SYSTEM_UID;
20 
21 import android.content.Context;
22 import android.net.wifi.WifiInfo;
23 import android.net.wifi.WifiManager;
24 import android.net.wifi.p2p.WifiP2pConfig;
25 import android.net.wifi.p2p.WifiP2pGroup;
26 import android.net.wifi.p2p.WifiP2pGroupList;
27 import android.util.Log;
28 
29 import com.android.server.wifi.Clock;
30 import com.android.server.wifi.proto.WifiStatsLog;
31 import com.android.server.wifi.proto.nano.WifiMetricsProto.GroupEvent;
32 import com.android.server.wifi.proto.nano.WifiMetricsProto.P2pConnectionEvent;
33 import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiP2pStats;
34 import com.android.server.wifi.util.StringUtil;
35 
36 import java.io.PrintWriter;
37 import java.util.ArrayList;
38 import java.util.Calendar;
39 import java.util.Collection;
40 import java.util.List;
41 
42 /**
43  * Provides storage for wireless connectivity P2p metrics, as they are generated.
44  * Metrics logged by this class include:
45  *   Aggregated connection stats (num of connections, num of failures, ...)
46  *   Discrete connection event stats (time, duration, failure codes, ...)
47  */
48 public class WifiP2pMetrics {
49     private static final String TAG = "WifiP2pMetrics";
50     private static final boolean DBG = false;
51 
52     private static final int MAX_CONNECTION_EVENTS = 256;
53     private static final int MAX_GROUP_EVENTS = 256;
54     private static final int MIN_2G_FREQUENCY_MHZ = 2412;
55 
56     private static final int MAX_CONNECTION_ATTEMPT_TIME_INTERVAL_MS = 30 * 1000;
57 
58     private Clock mClock;
59     private final Context mContext;
60     private final Object mLock = new Object();
61     private boolean mIsCountryCodeWorldMode = true;
62 
63     /**
64      * Metrics are stored within an instance of the WifiP2pStats proto during runtime,
65      * The P2pConnectionEvent and GroupEvent metrics are stored during runtime in member
66      * lists of this WifiP2pMetrics class, with the final WifiLog proto being pieced
67      * together at dump-time
68      */
69     private final WifiP2pStats mWifiP2pStatsProto =
70             new WifiP2pStats();
71 
72     /**
73      * Connection information that gets logged for every P2P connection attempt.
74      */
75     private final List<P2pConnectionEvent> mConnectionEventList =
76             new ArrayList<>();
77 
78     /**
79      * The latest started (but un-ended) connection attempt
80      */
81     private P2pConnectionEvent mCurrentConnectionEvent;
82 
83     /**
84      * The latest started (but un-ended) connection attempt start time
85      */
86     private long mCurrentConnectionEventStartTime;
87 
88     private long mLastConnectionEventStartTime;
89 
90     private int mLastConnectionEventUid;
91 
92     private int mLastConnectionTryCount;
93 
94     /**
95      * Group Session information that gets logged for every formed group.
96      */
97     private final List<GroupEvent> mGroupEventList =
98             new ArrayList<>();
99 
100     /**
101      * The latest started (but un-ended) group
102      */
103     private GroupEvent mCurrentGroupEvent;
104 
105     /**
106      * The latest started (but un-ended) group start time
107      */
108     private long mCurrentGroupEventStartTime;
109 
110     /**
111      * The latest started (but un-ended) group idle start time.
112      * The group is idle if there is no connected client.
113      */
114     private long mCurrentGroupEventIdleStartTime;
115 
116     /**
117      * The current number of persistent groups.
118      * This should be persisted after a dump.
119      */
120     private int mNumPersistentGroup;
121 
WifiP2pMetrics(Clock clock, Context context)122     public WifiP2pMetrics(Clock clock, Context context) {
123         mClock = clock;
124         mContext = context;
125         mNumPersistentGroup = 0;
126     }
127 
128     /**
129      * Clear all WifiP2pMetrics, except for currentConnectionEvent.
130      */
clear()131     public void clear() {
132         synchronized (mLock) {
133             mConnectionEventList.clear();
134             if (mCurrentConnectionEvent != null) {
135                 mConnectionEventList.add(mCurrentConnectionEvent);
136             }
137             mGroupEventList.clear();
138             if (mCurrentGroupEvent != null) {
139                 mGroupEventList.add(mCurrentGroupEvent);
140             }
141             mWifiP2pStatsProto.clear();
142         }
143     }
144 
145     /**
146      * Put all metrics that were being tracked separately into mWifiP2pStatsProto
147      */
consolidateProto()148     public WifiP2pStats consolidateProto() {
149         synchronized (mLock) {
150             mWifiP2pStatsProto.numPersistentGroup = mNumPersistentGroup;
151             int connectionEventCount = mConnectionEventList.size();
152             if (mCurrentConnectionEvent != null) {
153                 connectionEventCount--;
154             }
155             mWifiP2pStatsProto.connectionEvent =
156                     new P2pConnectionEvent[connectionEventCount];
157             for (int i = 0; i < connectionEventCount; i++) {
158                 mWifiP2pStatsProto.connectionEvent[i] = mConnectionEventList.get(i);
159             }
160 
161             int groupEventCount = mGroupEventList.size();
162             if (mCurrentGroupEvent != null) {
163                 groupEventCount--;
164             }
165             mWifiP2pStatsProto.groupEvent =
166                     new GroupEvent[groupEventCount];
167             for (int i = 0; i < groupEventCount; i++) {
168                 mWifiP2pStatsProto.groupEvent[i] = mGroupEventList.get(i);
169             }
170             return mWifiP2pStatsProto;
171         }
172     }
173 
174     /**
175      * Dump all WifiP2pMetrics. Collects some metrics at this time.
176      *
177      * @param pw PrintWriter for writing dump to
178      */
dump(PrintWriter pw)179     public void dump(PrintWriter pw) {
180         synchronized (mLock) {
181             pw.println("WifiP2pMetrics:");
182             pw.println("mConnectionEvents:");
183             for (P2pConnectionEvent event : mConnectionEventList) {
184                 StringBuilder sb = new StringBuilder();
185                 Calendar c = Calendar.getInstance();
186                 c.setTimeInMillis(event.startTimeMillis);
187                 sb.append("startTime=");
188                 if (event.startTimeMillis == 0) {
189                     sb.append("            <null>");
190                 } else {
191                     sb.append(StringUtil.calendarToString(c));
192                 }
193                 sb.append(", connectionType=");
194                 switch (event.connectionType) {
195                     case P2pConnectionEvent.CONNECTION_FRESH:
196                         sb.append("FRESH");
197                         break;
198                     case P2pConnectionEvent.CONNECTION_REINVOKE:
199                         sb.append("REINVOKE");
200                         break;
201                     case P2pConnectionEvent.CONNECTION_LOCAL:
202                         sb.append("LOCAL");
203                         break;
204                     case P2pConnectionEvent.CONNECTION_FAST:
205                         sb.append("FAST");
206                         break;
207                     default:
208                         sb.append("UNKNOWN");
209                         break;
210                 }
211                 sb.append(", wpsMethod=");
212                 switch (event.wpsMethod) {
213                     case P2pConnectionEvent.WPS_NA:
214                         sb.append("NA");
215                         break;
216                     case P2pConnectionEvent.WPS_PBC:
217                         sb.append("PBC");
218                         break;
219                     case P2pConnectionEvent.WPS_DISPLAY:
220                         sb.append("DISPLAY");
221                         break;
222                     case P2pConnectionEvent.WPS_KEYPAD:
223                         sb.append("KEYPAD");
224                         break;
225                     case P2pConnectionEvent.WPS_LABEL:
226                         sb.append("LABLE");
227                         break;
228                     default:
229                         sb.append("UNKNOWN");
230                         break;
231                 }
232                 sb.append(", durationTakenToConnectMillis=");
233                 sb.append(event.durationTakenToConnectMillis);
234                 sb.append(", groupRole=");
235                 switch (event.groupRole) {
236                     case GroupEvent.GROUP_OWNER:
237                         sb.append("OWNER");
238                         break;
239                     case GroupEvent.GROUP_CLIENT:
240                         sb.append("CLIENT");
241                         break;
242                     default:
243                         sb.append("UNKNOWN DURING CONNECT");
244                         break;
245                 }
246 
247                 sb.append(", tryCount=");
248                 sb.append(event.tryCount);
249                 sb.append(", inviteToNeg=");
250                 sb.append(event.fallbackToNegotiationOnInviteStatusInfoUnavailable);
251                 sb.append(", isCcWw=");
252                 sb.append(event.isCountryCodeWorldMode);
253                 sb.append(", band=");
254                 sb.append(event.band);
255                 sb.append(", freq=");
256                 sb.append(event.frequencyMhz);
257                 sb.append(", sta freq=");
258                 sb.append(event.staFrequencyMhz);
259                 sb.append(", uid=");
260                 sb.append(event.uid);
261                 sb.append(", connectivityLevelFailureCode=");
262                 switch (event.connectivityLevelFailureCode) {
263                     case P2pConnectionEvent.CLF_NONE:
264                         sb.append("NONE");
265                         break;
266                     case P2pConnectionEvent.CLF_TIMEOUT:
267                         sb.append("TIMEOUT");
268                         break;
269                     case P2pConnectionEvent.CLF_CANCEL:
270                         sb.append("CANCEL");
271                         break;
272                     case P2pConnectionEvent.CLF_PROV_DISC_FAIL:
273                         sb.append("PROV_DISC_FAIL");
274                         break;
275                     case P2pConnectionEvent.CLF_INVITATION_FAIL:
276                         sb.append("INVITATION_FAIL");
277                         break;
278                     case P2pConnectionEvent.CLF_USER_REJECT:
279                         sb.append("USER_REJECT");
280                         break;
281                     case P2pConnectionEvent.CLF_NEW_CONNECTION_ATTEMPT:
282                         sb.append("NEW_CONNECTION_ATTEMPT");
283                         break;
284                     case P2pConnectionEvent.CLF_GROUP_REMOVED:
285                         sb.append("GROUP_REMOVED");
286                         break;
287                     case P2pConnectionEvent.CLF_CREATE_GROUP_FAILED:
288                         sb.append("CREATE_GROUP_FAILED");
289                         break;
290                     case P2pConnectionEvent.CLF_UNKNOWN:
291                     default:
292                         sb.append("UNKNOWN");
293                         break;
294                 }
295                 if (event == mCurrentConnectionEvent) {
296                     sb.append(" CURRENTLY OPEN EVENT");
297                 }
298                 pw.println(sb.toString());
299             }
300             pw.println("mGroupEvents:");
301             for (GroupEvent event : mGroupEventList) {
302                 StringBuilder sb = new StringBuilder();
303                 Calendar c = Calendar.getInstance();
304                 c.setTimeInMillis(event.startTimeMillis);
305                 sb.append("netId=");
306                 sb.append(event.netId);
307                 sb.append(", startTime=");
308                 sb.append(event.startTimeMillis == 0 ? "            <null>" :
309                         String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
310                 sb.append(", channelFrequency=");
311                 sb.append(event.channelFrequency);
312                 sb.append(", groupRole=");
313                 switch (event.groupRole) {
314                     case GroupEvent.GROUP_CLIENT:
315                         sb.append("GroupClient");
316                         break;
317                     case GroupEvent.GROUP_OWNER:
318                     default:
319                         sb.append("GroupOwner");
320                         break;
321                 }
322                 sb.append(", numConnectedClients=");
323                 sb.append(event.numConnectedClients);
324                 sb.append(", numCumulativeClients=");
325                 sb.append(event.numCumulativeClients);
326                 sb.append(", sessionDurationMillis=");
327                 sb.append(event.sessionDurationMillis);
328                 sb.append(", idleDurationMillis=");
329                 sb.append(event.idleDurationMillis);
330 
331                 if (event == mCurrentGroupEvent) {
332                     sb.append(" CURRENTLY OPEN EVENT");
333                 }
334                 pw.println(sb.toString());
335             }
336             pw.println("mWifiP2pStatsProto.numPersistentGroup="
337                     + mNumPersistentGroup);
338             pw.println("mWifiP2pStatsProto.numTotalPeerScans="
339                     + mWifiP2pStatsProto.numTotalPeerScans);
340             pw.println("mWifiP2pStatsProto.numTotalServiceScans="
341                     + mWifiP2pStatsProto.numTotalServiceScans);
342         }
343     }
344 
345     /** Increment total number of peer scans */
incrementPeerScans()346     public void incrementPeerScans() {
347         synchronized (mLock) {
348             mWifiP2pStatsProto.numTotalPeerScans++;
349         }
350     }
351 
352     /** Increment total number of service scans */
incrementServiceScans()353     public void incrementServiceScans() {
354         synchronized (mLock) {
355             mWifiP2pStatsProto.numTotalServiceScans++;
356         }
357     }
358 
359     /** Set the number of saved persistent group */
updatePersistentGroup(WifiP2pGroupList groups)360     public void updatePersistentGroup(WifiP2pGroupList groups) {
361         synchronized (mLock) {
362             final Collection<WifiP2pGroup> list = groups.getGroupList();
363             mNumPersistentGroup = list.size();
364         }
365     }
366 
367     /** Returns if current connection event type is FAST connection */
isP2pFastConnectionType()368     public boolean isP2pFastConnectionType() {
369         if (mCurrentConnectionEvent == null) {
370             return false;
371         }
372         return P2pConnectionEvent.CONNECTION_FAST == mCurrentConnectionEvent.connectionType;
373     }
374 
375     /** Gets current connection event group role string */
getP2pGroupRoleString()376     public String getP2pGroupRoleString() {
377         if (mCurrentConnectionEvent == null) {
378             return "UNKNOWN";
379         }
380         return (GroupEvent.GROUP_OWNER == mCurrentConnectionEvent.groupRole) ? "GO" : "GC";
381     }
382 
383     /**
384      * Create a new connection event. Call when p2p attempts to make a new connection to
385      * another peer. If there is a current 'un-ended' connection event, it will be ended with
386      * P2pConnectionEvent.CLF_NEW_CONNECTION_ATTEMPT.
387      *
388      * @param connectionType indicate this connection is fresh or reinvoke.
389      * @param config configuration used for this connection.
390      * @param groupRole groupRole used for this connection.
391      */
startConnectionEvent(int connectionType, WifiP2pConfig config, int groupRole, int uid)392     public void startConnectionEvent(int connectionType, WifiP2pConfig config, int groupRole,
393             int uid) {
394         synchronized (mLock) {
395             // handle overlapping connection event first.
396             if (mCurrentConnectionEvent != null) {
397                 endConnectionEvent(P2pConnectionEvent.CLF_NEW_CONNECTION_ATTEMPT);
398             }
399 
400             while (mConnectionEventList.size() >= MAX_CONNECTION_EVENTS) {
401                 mConnectionEventList.remove(0);
402             }
403             mCurrentConnectionEventStartTime = mClock.getElapsedSinceBootMillis();
404 
405             mCurrentConnectionEvent = new P2pConnectionEvent();
406             mCurrentConnectionEvent.startTimeMillis = mClock.getWallClockMillis();
407             mCurrentConnectionEvent.connectionType = connectionType;
408             mCurrentConnectionEvent.groupRole = groupRole;
409 
410             if (config != null) {
411                 mCurrentConnectionEvent.wpsMethod = config.wps.setup;
412                 mCurrentConnectionEvent.band = convertGroupOwnerBand(config.groupOwnerBand);
413                 mCurrentConnectionEvent.frequencyMhz =
414                         (config.groupOwnerBand < MIN_2G_FREQUENCY_MHZ) ? 0 : config.groupOwnerBand;
415             }
416             mCurrentConnectionEvent.staFrequencyMhz = getWifiStaFrequency();
417             mCurrentConnectionEvent.uid = uid;
418             if (mLastConnectionEventUid == uid && mCurrentConnectionEventStartTime < (
419                     mLastConnectionEventStartTime + MAX_CONNECTION_ATTEMPT_TIME_INTERVAL_MS)) {
420                 mLastConnectionTryCount += 1;
421             } else {
422                 mLastConnectionTryCount = 1;
423             }
424             mLastConnectionEventUid = uid;
425             mLastConnectionEventStartTime = mCurrentConnectionEventStartTime;
426             mCurrentConnectionEvent.tryCount = mLastConnectionTryCount;
427 
428             mConnectionEventList.add(mCurrentConnectionEvent);
429         }
430     }
431 
432     /** Returns if there is an ongoing connection */
hasOngoingConnection()433     public boolean hasOngoingConnection() {
434         return mCurrentConnectionEvent != null;
435     }
436 
437     /**
438      * End a Connection event record. Call when p2p connection attempt succeeds or fails.
439      * If a Connection event has not been started when .end is called,
440      * a new one is created with zero duration.
441      *
442      * @param failure indicate the failure with WifiMetricsProto.P2pConnectionEvent.CLF_X.
443      */
endConnectionEvent(int failure)444     public void endConnectionEvent(int failure) {
445         synchronized (mLock) {
446             if (mCurrentConnectionEvent == null) {
447                 // Reinvoking a group with invitation will be handled in supplicant.
448                 // There won't be a connection starting event in framework.
449                 // THe framework only get the connection ending event in GroupStarted state.
450                 startConnectionEvent(P2pConnectionEvent.CONNECTION_REINVOKE, null,
451                         GroupEvent.GROUP_UNKNOWN, SYSTEM_UID);
452             }
453 
454             mCurrentConnectionEvent.durationTakenToConnectMillis = (int)
455                     (mClock.getElapsedSinceBootMillis()
456                     - mCurrentConnectionEventStartTime);
457             mCurrentConnectionEvent.connectivityLevelFailureCode = failure;
458             mCurrentConnectionEvent.isCountryCodeWorldMode = mIsCountryCodeWorldMode;
459 
460             WifiStatsLog.write(WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED,
461                     convertConnectionType(mCurrentConnectionEvent.connectionType),
462                     mCurrentConnectionEvent.durationTakenToConnectMillis,
463                     mCurrentConnectionEvent.durationTakenToConnectMillis / 200,
464                     convertFailureCode(failure),
465                     convertGroupRole(mCurrentConnectionEvent.groupRole),
466                     convertBandStatsLog(mCurrentConnectionEvent.band),
467                     mCurrentConnectionEvent.frequencyMhz,
468                     mCurrentConnectionEvent.staFrequencyMhz,
469                     mCurrentConnectionEvent.uid,
470                     mIsCountryCodeWorldMode,
471                     mCurrentConnectionEvent.fallbackToNegotiationOnInviteStatusInfoUnavailable,
472                     mCurrentConnectionEvent.tryCount);
473             mCurrentConnectionEvent = null;
474             if (P2pConnectionEvent.CLF_NONE == failure) {
475                 mLastConnectionTryCount = 0;
476             }
477         }
478     }
479 
480     /**
481      * Fallback to GO negotiation if device receives invitation response status code -
482      * information is currently unavailable
483      */
setFallbackToNegotiationOnInviteStatusInfoUnavailable()484     public void setFallbackToNegotiationOnInviteStatusInfoUnavailable() {
485         if (mCurrentConnectionEvent == null) {
486             return;
487         }
488         mCurrentConnectionEvent.fallbackToNegotiationOnInviteStatusInfoUnavailable = true;
489     }
490 
491    /** Sets if the Country Code is in world mode */
setIsCountryCodeWorldMode(boolean isCountryCodeWorldMode)492     public void setIsCountryCodeWorldMode(boolean isCountryCodeWorldMode) {
493         mIsCountryCodeWorldMode = isCountryCodeWorldMode;
494     }
495 
convertConnectionType(int connectionType)496     private int convertConnectionType(int connectionType) {
497         switch (connectionType) {
498             case P2pConnectionEvent.CONNECTION_FRESH:
499                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__TYPE__FRESH;
500             case P2pConnectionEvent.CONNECTION_REINVOKE:
501                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__TYPE__REINVOKE;
502             case P2pConnectionEvent.CONNECTION_LOCAL:
503                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__TYPE__LOCAL;
504             case P2pConnectionEvent.CONNECTION_FAST:
505                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__TYPE__FAST;
506             default:
507                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__TYPE__UNSPECIFIED;
508         }
509     }
510 
convertFailureCode(int failureCode)511     private int convertFailureCode(int failureCode) {
512         switch (failureCode) {
513             case P2pConnectionEvent.CLF_NONE:
514                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__FAILURE_CODE__NONE;
515             case P2pConnectionEvent.CLF_TIMEOUT:
516                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__FAILURE_CODE__TIMEOUT;
517             case P2pConnectionEvent.CLF_CANCEL:
518                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__FAILURE_CODE__CANCEL;
519             case P2pConnectionEvent.CLF_PROV_DISC_FAIL:
520                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__FAILURE_CODE__PROV_DISC_FAIL;
521             case P2pConnectionEvent.CLF_INVITATION_FAIL:
522                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__FAILURE_CODE__INVITATION_FAIL;
523             case P2pConnectionEvent.CLF_USER_REJECT:
524                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__FAILURE_CODE__USER_REJECT;
525             case P2pConnectionEvent.CLF_NEW_CONNECTION_ATTEMPT:
526                 return WifiStatsLog
527                         .WIFI_P2P_CONNECTION_REPORTED__FAILURE_CODE__NEW_CONNECTION_ATTEMPT;
528             case P2pConnectionEvent.CLF_GROUP_REMOVED:
529                 return WifiStatsLog
530                         .WIFI_P2P_CONNECTION_REPORTED__FAILURE_CODE__GROUP_REMOVED;
531             case P2pConnectionEvent.CLF_CREATE_GROUP_FAILED:
532                 return WifiStatsLog
533                         .WIFI_P2P_CONNECTION_REPORTED__FAILURE_CODE__CREATE_GROUP_FAILED;
534             case P2pConnectionEvent.CLF_UNKNOWN:
535             default:
536                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__FAILURE_CODE__UNKNOWN;
537         }
538     }
539 
convertGroupRole(int groupRole)540     private int convertGroupRole(int groupRole) {
541         switch (groupRole) {
542             case GroupEvent.GROUP_OWNER:
543                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__GROUP_ROLE__GROUP_OWNER;
544             case GroupEvent.GROUP_CLIENT:
545                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__GROUP_ROLE__GROUP_CLIENT;
546             default:
547                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__GROUP_ROLE__GROUP_UNKNOWN;
548         }
549     }
550 
convertGroupOwnerBand(int bandOrFrequency)551     private int convertGroupOwnerBand(int bandOrFrequency) {
552         if (bandOrFrequency >= MIN_2G_FREQUENCY_MHZ) {
553             return P2pConnectionEvent.BAND_FREQUENCY;
554         } else {
555             switch (bandOrFrequency) {
556                 case WifiP2pConfig.GROUP_OWNER_BAND_AUTO:
557                     return P2pConnectionEvent.BAND_AUTO;
558                 case WifiP2pConfig.GROUP_OWNER_BAND_2GHZ:
559                     return P2pConnectionEvent.BAND_2G;
560                 case WifiP2pConfig.GROUP_OWNER_BAND_5GHZ:
561                     return P2pConnectionEvent.BAND_5G;
562                 default:
563                     return P2pConnectionEvent.BAND_UNKNOWN;
564             }
565         }
566     }
567 
convertBandStatsLog(int band)568     private int convertBandStatsLog(int band) {
569         switch (band) {
570             case P2pConnectionEvent.BAND_AUTO:
571                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__BAND__BAND_AUTO;
572             case P2pConnectionEvent.BAND_2G:
573                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__BAND__BAND_2G;
574             case P2pConnectionEvent.BAND_5G:
575                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__BAND__BAND_5G;
576             case P2pConnectionEvent.BAND_6G:
577                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__BAND__BAND_6G;
578             case P2pConnectionEvent.BAND_FREQUENCY:
579                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__BAND__BAND_FREQUENCY;
580             default:
581                 return WifiStatsLog.WIFI_P2P_CONNECTION_REPORTED__BAND__BAND_UNKNOWN;
582         }
583     }
584 
getWifiStaFrequency()585     private int getWifiStaFrequency() {
586         WifiManager wifiManager = mContext.getSystemService(WifiManager.class);
587         WifiInfo wifiInfo = wifiManager.getConnectionInfo();
588         if (wifiInfo.getFrequency() > 0) {
589             return wifiInfo.getFrequency();
590         } else {
591             return 0;
592         }
593     }
594 
595     /**
596      * Create a new group event.
597      *
598      * @param group the information of started group.
599      */
startGroupEvent(WifiP2pGroup group)600     public void startGroupEvent(WifiP2pGroup group) {
601         if (group == null) {
602             if (DBG) Log.d(TAG, "Cannot start group event due to null group");
603             return;
604         }
605         synchronized (mLock) {
606             // handle overlapping group event first.
607             if (mCurrentGroupEvent != null) {
608                 if (DBG) Log.d(TAG, "Overlapping group event!");
609                 endGroupEvent();
610             }
611 
612             while (mGroupEventList.size() >= MAX_GROUP_EVENTS) {
613                 mGroupEventList.remove(0);
614             }
615             mCurrentGroupEventStartTime = mClock.getElapsedSinceBootMillis();
616             if (group.getClientList().size() == 0) {
617                 mCurrentGroupEventIdleStartTime = mClock.getElapsedSinceBootMillis();
618             } else {
619                 mCurrentGroupEventIdleStartTime = 0;
620             }
621 
622             mCurrentGroupEvent = new GroupEvent();
623             mCurrentGroupEvent.netId = group.getNetworkId();
624             mCurrentGroupEvent.startTimeMillis = mClock.getWallClockMillis();
625             mCurrentGroupEvent.numConnectedClients = group.getClientList().size();
626             mCurrentGroupEvent.channelFrequency = group.getFrequency();
627             mCurrentGroupEvent.groupRole = group.isGroupOwner()
628                     ? GroupEvent.GROUP_OWNER
629                     : GroupEvent.GROUP_CLIENT;
630             mGroupEventList.add(mCurrentGroupEvent);
631         }
632     }
633 
634     /**
635      * Update the information of started group.
636      */
updateGroupEvent(WifiP2pGroup group)637     public void updateGroupEvent(WifiP2pGroup group) {
638         if (group == null) {
639             if (DBG) Log.d(TAG, "Cannot update group event due to null group.");
640             return;
641         }
642         synchronized (mLock) {
643             if (mCurrentGroupEvent == null) {
644                 Log.w(TAG, "Cannot update group event due to no current group.");
645                 return;
646             }
647 
648             if (mCurrentGroupEvent.netId != group.getNetworkId()) {
649                 Log.w(TAG, "Updating group id " + group.getNetworkId()
650                         + " is different from current group id " + mCurrentGroupEvent.netId
651                         + ".");
652                 return;
653             }
654 
655             int delta = group.getClientList().size() - mCurrentGroupEvent.numConnectedClients;
656             mCurrentGroupEvent.numConnectedClients = group.getClientList().size();
657             if (delta > 0) {
658                 mCurrentGroupEvent.numCumulativeClients += delta;
659             }
660 
661             // if new client comes during idle period, cumulate idle duration and reset idle timer.
662             // if the last client disconnected during non-idle period, start idle timer.
663             if (mCurrentGroupEventIdleStartTime > 0) {
664                 if (group.getClientList().size() > 0) {
665                     mCurrentGroupEvent.idleDurationMillis +=
666                             (mClock.getElapsedSinceBootMillis()
667                             - mCurrentGroupEventIdleStartTime);
668                     mCurrentGroupEventIdleStartTime = 0;
669                 }
670             } else {
671                 if (group.getClientList().size() == 0) {
672                     mCurrentGroupEventIdleStartTime = mClock.getElapsedSinceBootMillis();
673                 }
674             }
675         }
676     }
677 
678     /**
679      * End a group event.
680      */
endGroupEvent()681     public void endGroupEvent() {
682         synchronized (mLock) {
683             if (mCurrentGroupEvent != null) {
684                 mCurrentGroupEvent.sessionDurationMillis = (int)
685                         (mClock.getElapsedSinceBootMillis()
686                         - mCurrentGroupEventStartTime);
687                 if (mCurrentGroupEventIdleStartTime > 0) {
688                     mCurrentGroupEvent.idleDurationMillis +=
689                             (mClock.getElapsedSinceBootMillis()
690                             - mCurrentGroupEventIdleStartTime);
691                     mCurrentGroupEventIdleStartTime = 0;
692                 }
693             } else {
694                 Log.e(TAG, "No current group!");
695             }
696             mCurrentGroupEvent = null;
697         }
698     }
699 
700     /* Log Metrics */
701 }
702