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