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