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.server.am; 18 19 import static android.app.ActivityManager.FOREGROUND_SERVICE_API_TYPE_AUDIO; 20 import static android.app.ActivityManager.FOREGROUND_SERVICE_API_TYPE_BLUETOOTH; 21 import static android.app.ActivityManager.FOREGROUND_SERVICE_API_TYPE_CAMERA; 22 import static android.app.ActivityManager.FOREGROUND_SERVICE_API_TYPE_CDM; 23 import static android.app.ActivityManager.FOREGROUND_SERVICE_API_TYPE_LOCATION; 24 import static android.app.ActivityManager.FOREGROUND_SERVICE_API_TYPE_MEDIA_PLAYBACK; 25 import static android.app.ActivityManager.FOREGROUND_SERVICE_API_TYPE_MICROPHONE; 26 import static android.app.ActivityManager.FOREGROUND_SERVICE_API_TYPE_PHONE_CALL; 27 import static android.app.ActivityManager.FOREGROUND_SERVICE_API_TYPE_USB; 28 import static android.os.Process.INVALID_UID; 29 30 import static com.android.internal.util.FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA; 31 32 import android.annotation.IntDef; 33 import android.app.ActivityManager; 34 import android.app.ActivityManager.ForegroundServiceApiType; 35 import android.app.ForegroundServiceDelegationOptions; 36 import android.content.ComponentName; 37 import android.content.pm.ServiceInfo; 38 import android.os.Trace; 39 import android.util.ArrayMap; 40 import android.util.IntArray; 41 import android.util.LongArray; 42 import android.util.Slog; 43 import android.util.SparseArray; 44 import android.util.SparseIntArray; 45 46 import com.android.internal.annotations.VisibleForTesting; 47 import com.android.internal.util.FrameworkStatsLog; 48 49 import java.lang.annotation.Retention; 50 import java.lang.annotation.RetentionPolicy; 51 import java.util.ArrayList; 52 53 /** 54 * Responsible for handling logging of API events 55 * and associating APIs with currently running FGS. 56 * Also tracks FGS that are currently running. 57 */ 58 public class ForegroundServiceTypeLoggerModule { 59 60 private static final String TAG = "ForegroundServiceTypeLoggerModule"; 61 62 public static final int FGS_STATE_CHANGED_API_CALL = 4; 63 64 public static final int FGS_API_BEGIN_WITH_FGS = 1; 65 public static final int FGS_API_END_WITH_FGS = 2; 66 public static final int FGS_API_END_WITHOUT_FGS = 3; 67 public static final int FGS_API_PAUSE = 4; 68 public static final int FGS_API_RESUME = 5; 69 70 @IntDef(flag = false, prefix = { "FGS_API_" }, value = { 71 FGS_API_BEGIN_WITH_FGS, 72 FGS_API_END_WITH_FGS, 73 FGS_API_END_WITHOUT_FGS, 74 FGS_API_PAUSE, 75 FGS_API_RESUME, 76 }) 77 @Retention(RetentionPolicy.SOURCE) 78 public @interface FgsApiState {} 79 80 81 private static class UidState { 82 // A stack that keeps a list of API calls by type. 83 // This represents the ongoing open APIs 84 // that are running on the system for each 85 // app in the system. They are keyed 86 // by the API type (represented as a number). 87 final SparseArray<FgsApiRecord> mApiOpenCalls = new SparseArray<>(); 88 89 // This stack represents the last close call made per type 90 // We only care about the last call made so we track the last close 91 // call made per type. This way, once the FGS closes 92 // we simply log the last API call made. 93 final SparseArray<FgsApiRecord> mApiClosedCalls = new SparseArray<>(); 94 95 // Here we track how many APIs are opened before any FGS is running. 96 // These counts will only be added to the open call count below if 97 // an FGS is started. If an FGS is NOT started, then this count should 98 // gradually hit zero as close calls are decremented. 99 final SparseIntArray mOpenedWithoutFgsCount = new SparseIntArray(); 100 101 // Here we keep track of the count of in-flight calls. 102 // We only want to log the first open call and the last 103 // close call so that we get the largest duration 104 // possible. 105 final SparseIntArray mOpenWithFgsCount = new SparseIntArray(); 106 107 // A stack that keeps a list of API calls in the order 108 // that they were called. This represents the ongoing 109 // open APIs that are running on the system for each 110 // app in the system. They are keyed by FGS Type 111 // to another ordered map, keyed by the component name 112 // to facilitate removing the record from the structure 113 final SparseArray<ArrayMap<ComponentName, ServiceRecord>> mRunningFgs = new SparseArray<>(); 114 115 // A map of API types to last FGS stop call timestamps 116 // We use this to get the duration an API was active after 117 // the stop call. 118 final SparseArray<Long> mLastFgsTimeStamp = new SparseArray<>(); 119 120 // A map of API types to first FGS start call timestamps 121 // We use this to get the duration an API was active after 122 // the stop call. 123 final SparseArray<Long> mFirstFgsTimeStamp = new SparseArray<>(); 124 } 125 126 // SparseArray that tracks all UIDs that have made various 127 // API calls. Keyed by UID. 128 private final SparseArray<UidState> mUids = new SparseArray<>(); 129 ForegroundServiceTypeLoggerModule()130 public ForegroundServiceTypeLoggerModule() { 131 } 132 133 /** 134 * Used to log the start of a Foreground Service. The first API 135 * call of the right type will also be associated and logged 136 */ logForegroundServiceStart(int uid, int pid, ServiceRecord record)137 public void logForegroundServiceStart(int uid, int pid, ServiceRecord record) { 138 if (record.getComponentName() != null) { 139 final String traceTag = record.getComponentName().flattenToString() + ":" + uid; 140 Trace.asyncTraceForTrackBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, traceTag, 141 "foregroundService", record.foregroundServiceType); 142 } 143 // initialize the UID stack 144 UidState uidState = mUids.get(uid); 145 if (uidState == null) { 146 uidState = new UidState(); 147 mUids.put(uid, uidState); 148 } 149 // grab the appropriate types 150 final IntArray apiTypes = 151 convertFgsTypeToApiTypes(record.foregroundServiceType); 152 if (apiTypes.size() == 0) { 153 Slog.w(TAG, "Foreground service start for UID: " 154 + uid + " does not have any types"); 155 } 156 // now we need to iterate through the types 157 // and insert the new record as needed 158 final IntArray apiTypesFound = new IntArray(); 159 final LongArray timestampsFound = new LongArray(); 160 for (int i = 0, size = apiTypes.size(); i < size; i++) { 161 final int apiType = apiTypes.get(i); 162 int fgsIndex = uidState.mRunningFgs.indexOfKey(apiType); 163 if (fgsIndex < 0) { 164 uidState.mRunningFgs.put(apiType, new ArrayMap<>()); 165 fgsIndex = uidState.mRunningFgs.indexOfKey(apiType); 166 uidState.mFirstFgsTimeStamp.put(apiType, System.currentTimeMillis()); 167 } 168 final ArrayMap<ComponentName, ServiceRecord> fgsList = 169 uidState.mRunningFgs.valueAt(fgsIndex); 170 fgsList.put(record.getComponentName(), record); 171 // now we want to figure out if this FGS is associated with any currently open API 172 173 // retrieve the last API call for the type if there is one 174 if (uidState.mApiOpenCalls.contains(apiType)) { 175 // update the open call count associated with an FGS 176 // we want to dump the previously opened call count into the 177 // opened with an FGS call count 178 // then zero out the old count 179 uidState.mOpenWithFgsCount 180 .put(apiType, uidState.mOpenedWithoutFgsCount.get(apiType)); 181 uidState.mOpenedWithoutFgsCount.put(apiType, 0); 182 apiTypesFound.add(apiType); 183 final FgsApiRecord call = uidState.mApiOpenCalls.get(apiType); 184 timestampsFound.add(call.mTimeStart); 185 // associate the call 186 call.mIsAssociatedWithFgs = true; 187 call.mAssociatedFgsRecord = record; 188 189 // remove the APIs, since we've logged the API starts 190 // so we don't need to log them again 191 uidState.mApiOpenCalls.remove(apiType); 192 } 193 } 194 if (apiTypesFound.size() != 0) { 195 // log a state change 196 for (int i = 0, size = apiTypesFound.size(); i < size; i++) { 197 logFgsApiEvent(record, 198 FGS_STATE_CHANGED_API_CALL, 199 FGS_API_BEGIN_WITH_FGS, 200 apiTypesFound.get(i), 201 timestampsFound.get(i)); 202 } 203 } 204 } 205 206 /** 207 * Logs when an FGS stops. The last associated closed API event 208 * will also be logged 209 */ logForegroundServiceStop(int uid, ServiceRecord record)210 public void logForegroundServiceStop(int uid, ServiceRecord record) { 211 // we need to log all the API end events and remove the start events 212 // then we remove the FGS from the various stacks 213 // and also clean up the start calls stack by UID 214 if (record.getComponentName() != null) { 215 final String traceTag = record.getComponentName().flattenToString() + ":" + uid; 216 Trace.asyncTraceForTrackEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, 217 traceTag, record.hashCode()); 218 } 219 final IntArray apiTypes = convertFgsTypeToApiTypes(record.foregroundServiceType); 220 final UidState uidState = mUids.get(uid); 221 if (apiTypes.size() == 0) { 222 Slog.w(TAG, "FGS stop call for: " + uid + " has no types!"); 223 } 224 if (uidState == null) { 225 Slog.w(TAG, "FGS stop call being logged with no start call for UID for UID " 226 + uid 227 + " in package " + record.packageName); 228 return; 229 } 230 final ArrayList<Integer> apisFound = new ArrayList<>(); 231 final ArrayList<Long> timestampsFound = new ArrayList<>(); 232 for (int i = 0, size = apiTypes.size(); i < size; i++) { 233 final int apiType = apiTypes.get(i); 234 235 // remove the FGS record from the stack 236 final ArrayMap<ComponentName, ServiceRecord> runningFgsOfType = 237 uidState.mRunningFgs.get(apiType); 238 if (runningFgsOfType == null) { 239 Slog.w(TAG, "Could not find appropriate running FGS for FGS stop for UID " + uid 240 + " in package " + record.packageName); 241 continue; 242 } 243 244 runningFgsOfType.remove(record.getComponentName()); 245 if (runningFgsOfType.size() == 0) { 246 // there's no more FGS running for this type, just get rid of it 247 uidState.mRunningFgs.remove(apiType); 248 // but we need to keep track of the timestamp in case an API stops 249 uidState.mLastFgsTimeStamp.put(apiType, System.currentTimeMillis()); 250 } 251 252 final int apiTypeIndex = uidState.mOpenWithFgsCount.indexOfKey(apiType); 253 if (apiTypeIndex < 0) { 254 Slog.w(TAG, "Logger should be tracking FGS types correctly for UID " + uid 255 + " in package " + record.packageName); 256 continue; 257 } 258 // retrieve the eligible closed call 259 // we only want to log if this is the only 260 // open in flight call. If there are other calls, 261 // we just skip logging 262 final FgsApiRecord closedApi = uidState.mApiClosedCalls.get(apiType); 263 if (closedApi != null 264 && uidState.mOpenWithFgsCount.valueAt(apiTypeIndex) == 0) { 265 apisFound.add(apiType); 266 timestampsFound.add(closedApi.mTimeStart); 267 // remove the last API close call 268 uidState.mApiClosedCalls.remove(apiType); 269 } 270 } 271 if (!apisFound.isEmpty()) { 272 // time to log the call 273 for (int i = 0; i < apisFound.size(); i++) { 274 logFgsApiEvent(record, 275 FGS_STATE_CHANGED_API_CALL, 276 FGS_API_END_WITH_FGS, apisFound.get(i), timestampsFound.get(i)); 277 } 278 } 279 } 280 281 /** 282 * Called to log an API start call. If any associated FGS 283 * is running and this is the first open API call, then 284 * the event is logged. 285 */ logForegroundServiceApiEventBegin(@oregroundServiceApiType int apiType, int uid, int pid, String packageName)286 public long logForegroundServiceApiEventBegin(@ForegroundServiceApiType int apiType, 287 int uid, int pid, String packageName) { 288 final FgsApiRecord callStart = 289 new FgsApiRecord(uid, pid, packageName, apiType, System.currentTimeMillis()); 290 UidState uidState = mUids.get(uid); 291 if (uidState == null) { 292 uidState = new UidState(); 293 mUids.put(uid, uidState); 294 } 295 // now we want to figure out if this call is associated with any FGS 296 // is there an FGS? 297 if (!hasValidActiveFgs(uid, apiType)) { 298 // no FGS running currently, so this API 299 // started without an FGS 300 // initialize the started without FGS count if it isn't already 301 int openWithoutFgsCountIndex = 302 uidState.mOpenedWithoutFgsCount.indexOfKey(apiType); 303 304 if (openWithoutFgsCountIndex < 0) { 305 uidState.mOpenedWithoutFgsCount.put(apiType, 0); 306 openWithoutFgsCountIndex = 307 uidState.mOpenedWithoutFgsCount.indexOfKey(apiType); 308 } 309 // insert this record as the first open API call 310 // IF we do not have one 311 if (!uidState.mApiOpenCalls.contains(apiType) 312 || uidState.mOpenedWithoutFgsCount.valueAt(openWithoutFgsCountIndex) == 0) { 313 uidState.mApiOpenCalls.put(apiType, callStart); 314 } 315 // now update the count of the open API calls 316 // started without an FGS 317 uidState.mOpenedWithoutFgsCount 318 .put(apiType, uidState.mOpenedWithoutFgsCount.get(apiType) + 1); 319 return callStart.mTimeStart; 320 } 321 // so there is an FGS running 322 // that we can associate with 323 // we now need to update the count 324 // for open calls that started 325 // with an FGS 326 int openWithFgsIndex = uidState.mOpenWithFgsCount.indexOfKey(apiType); 327 328 if (openWithFgsIndex < 0) { 329 uidState.mOpenWithFgsCount.put(apiType, 0); 330 openWithFgsIndex = uidState.mOpenWithFgsCount.indexOfKey(apiType); 331 } 332 uidState.mOpenWithFgsCount 333 .put(apiType, uidState.mOpenWithFgsCount.valueAt(openWithFgsIndex) + 1); 334 final ArrayMap<ComponentName, ServiceRecord> fgsListMap = uidState.mRunningFgs.get(apiType); 335 336 // now we get the relevant FGS to log with 337 final int apiTypes = apiType; 338 final long timestamps = callStart.mTimeStart; 339 if (uidState.mOpenWithFgsCount.valueAt(openWithFgsIndex) == 1) { 340 for (ServiceRecord record : fgsListMap.values()) { 341 logFgsApiEvent(record, 342 FGS_STATE_CHANGED_API_CALL, 343 FGS_API_BEGIN_WITH_FGS, 344 apiTypes, 345 timestamps); 346 } 347 } 348 return callStart.mTimeStart; 349 } 350 351 /** 352 * Called to log the end of an API call. If this 353 * is the last API close call, it will be logged 354 * as an event. 355 */ logForegroundServiceApiEventEnd(@oregroundServiceApiType int apiType, int uid, int pid)356 public long logForegroundServiceApiEventEnd(@ForegroundServiceApiType int apiType, 357 int uid, int pid) { 358 // are there even FGS that we want to associate with? 359 // if there's even an entry in the open call count, 360 // then we should care, otherwise we assume 361 // it's not related to any FGS 362 UidState uidState = mUids.get(uid); 363 if (uidState == null) { 364 Slog.w(TAG, "API event end called before start!"); 365 return -1; 366 } 367 final int apiIndex = uidState.mOpenWithFgsCount.indexOfKey(apiType); 368 if (apiIndex >= 0) { 369 // are there any calls that started with an FGS? 370 if (uidState.mOpenWithFgsCount.get(apiType) != 0) { 371 // we should decrement the count, since we only 372 // want to log the last close call 373 uidState.mOpenWithFgsCount.put(apiType, 374 uidState.mOpenWithFgsCount.get(apiType) - 1); 375 } 376 // is there no FGS running and this is the last close call? 377 if (!hasValidActiveFgs(uid, apiType) 378 && uidState.mOpenWithFgsCount.get(apiType) == 0) { 379 // we just log that an event happened w/ no 380 // FGS associated. This is to avoid dangling 381 // events 382 final long timestamp = System.currentTimeMillis(); 383 final int apiTypes = apiType; 384 logFgsApiEventWithNoFgs(uid, FGS_API_END_WITHOUT_FGS, apiTypes, timestamp); 385 // we should now remove the count, so as to signal that 386 // there was never an FGS called that can be associated 387 uidState.mOpenWithFgsCount.removeAt(apiIndex); 388 return timestamp; 389 } 390 } 391 // we know now that this call is not coming from an 392 // open FGS associated API call. So it is likely 393 // a part of an unassociated call that has now been 394 // closed. So we decrement that count 395 if (uidState.mOpenedWithoutFgsCount.indexOfKey(apiType) < 0) { 396 // initialize if we don't contain 397 uidState.mOpenedWithoutFgsCount.put(apiType, 0); 398 } 399 int apiOpenWithoutFgsCount = uidState.mOpenedWithoutFgsCount.get(apiType); 400 if (apiOpenWithoutFgsCount != 0) { 401 apiOpenWithoutFgsCount -= 1; 402 if (apiOpenWithoutFgsCount == 0) { 403 uidState.mApiOpenCalls.remove(apiType); 404 } 405 uidState.mOpenedWithoutFgsCount 406 .put(apiType, apiOpenWithoutFgsCount); 407 return System.currentTimeMillis(); 408 } 409 // This is a part of a valid active FGS 410 // we should definitely update the pointer to the 411 // last closed API call 412 final SparseArray<FgsApiRecord> callsByUid = uidState.mApiClosedCalls; 413 final FgsApiRecord closedCall = 414 new FgsApiRecord(uid, pid, "", apiType, System.currentTimeMillis()); 415 uidState.mApiClosedCalls.put(apiType, closedCall); 416 return closedCall.mTimeStart; 417 } 418 419 /** 420 * Log an API state change. This is only to be used by media playback 421 */ logForegroundServiceApiStateChanged(@oregroundServiceApiType int apiType, int uid, int pid, int state)422 public void logForegroundServiceApiStateChanged(@ForegroundServiceApiType int apiType, 423 int uid, int pid, int state) { 424 UidState uidState = mUids.get(uid); 425 if (!uidState.mRunningFgs.contains(apiType)) { 426 // if there is no FGS running for this type that could mean that 427 // either the FGS was stopped a while ago or 428 // that the API call was never run with an FGS 429 return; 430 } 431 final ArrayMap<ComponentName, ServiceRecord> fgsRecords = uidState.mRunningFgs.get(apiType); 432 final int apiTypes = apiType; 433 final long timestamp = System.currentTimeMillis(); 434 for (ServiceRecord record : fgsRecords.values()) { 435 logFgsApiEvent(record, 436 FGS_STATE_CHANGED_API_CALL, 437 state, 438 apiTypes, 439 timestamp); 440 } 441 } 442 convertFgsTypeToApiTypes(int fgsType)443 private IntArray convertFgsTypeToApiTypes(int fgsType) { 444 final IntArray types = new IntArray(); 445 if ((fgsType & ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA) 446 == ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA) { 447 types.add(FOREGROUND_SERVICE_API_TYPE_CAMERA); 448 } 449 if ((fgsType & ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE) 450 == ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE) { 451 types.add(FOREGROUND_SERVICE_API_TYPE_BLUETOOTH); 452 types.add(FOREGROUND_SERVICE_API_TYPE_USB); 453 types.add(FOREGROUND_SERVICE_API_TYPE_CDM); 454 } 455 if ((fgsType & ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) 456 == ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) { 457 types.add(FOREGROUND_SERVICE_API_TYPE_LOCATION); 458 } 459 if ((fgsType & ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK) 460 == ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK) { 461 types.add(FOREGROUND_SERVICE_API_TYPE_AUDIO); 462 types.add(FOREGROUND_SERVICE_API_TYPE_MEDIA_PLAYBACK); 463 } 464 if ((fgsType & ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE) 465 == ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE) { 466 types.add(FOREGROUND_SERVICE_API_TYPE_MICROPHONE); 467 } 468 if ((fgsType & ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL) 469 == ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL) { 470 types.add(FOREGROUND_SERVICE_API_TYPE_PHONE_CALL); 471 } 472 return types; 473 } 474 hasValidActiveFgs(int uid, @ForegroundServiceApiType int apiType)475 private boolean hasValidActiveFgs(int uid, @ForegroundServiceApiType int apiType) { 476 UidState uidState = mUids.get(uid); 477 if (uidState != null) { 478 return uidState.mRunningFgs.contains(apiType); 479 } 480 return false; 481 } 482 483 /** 484 * Logs an API event that occurred while an FGS was running 485 */ 486 @VisibleForTesting logFgsApiEvent(ServiceRecord r, int fgsState, @FgsApiState int apiState, @ForegroundServiceApiType int apiType, long timestamp)487 public void logFgsApiEvent(ServiceRecord r, int fgsState, 488 @FgsApiState int apiState, 489 @ForegroundServiceApiType int apiType, long timestamp) { 490 long apiDurationBeforeFgsStart = 0; 491 long apiDurationAfterFgsEnd = 0; 492 UidState uidState = mUids.get(r.appInfo.uid); 493 if (uidState == null) { 494 return; 495 } 496 if (uidState.mFirstFgsTimeStamp.contains(apiType)) { 497 apiDurationBeforeFgsStart = uidState.mFirstFgsTimeStamp.get(apiType) - timestamp; 498 } 499 if (uidState.mLastFgsTimeStamp.contains(apiType)) { 500 apiDurationAfterFgsEnd = timestamp - uidState.mLastFgsTimeStamp.get(apiType); 501 } 502 final int[] apiTypes = new int[1]; 503 apiTypes[0] = apiType; 504 final long[] timeStamps = new long[1]; 505 timeStamps[0] = timestamp; 506 FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED, 507 r.appInfo.uid, 508 r.shortInstanceName, 509 fgsState, // FGS State 510 // TODO: Also log "forStart" 511 r.isFgsAllowedWiu_forCapabilities(), // allowWhileInUsePermissionInFgs 512 r.getFgsAllowStart(), // fgsStartReasonCode 513 r.appInfo.targetSdkVersion, 514 r.mRecentCallingUid, 515 0, // callerTargetSdkVersion 516 r.mInfoTempFgsAllowListReason != null 517 ? r.mInfoTempFgsAllowListReason.mCallingUid : INVALID_UID, 518 r.mFgsNotificationWasDeferred, 519 r.mFgsNotificationShown, 520 0, // durationMs 521 r.mStartForegroundCount, 522 0, // Short instance name -- no longer logging it. 523 r.mFgsHasNotificationPermission, 524 r.foregroundServiceType, 525 0, 526 r.mIsFgsDelegate, 527 r.mFgsDelegation != null ? r.mFgsDelegation.mOptions.mClientUid : INVALID_UID, 528 r.mFgsDelegation != null ? r.mFgsDelegation.mOptions.mDelegationService 529 : ForegroundServiceDelegationOptions.DELEGATION_SERVICE_DEFAULT, 530 apiState, 531 apiTypes, 532 timeStamps, 533 ActivityManager.PROCESS_STATE_UNKNOWN, 534 ActivityManager.PROCESS_CAPABILITY_NONE, 535 ActivityManager.PROCESS_STATE_UNKNOWN, 536 ActivityManager.PROCESS_CAPABILITY_NONE, 537 apiDurationBeforeFgsStart, 538 apiDurationAfterFgsEnd, 539 r.mAllowWiu_noBinding, 540 r.mAllowWiu_inBindService, 541 r.mAllowWiu_byBindings, 542 r.mAllowStart_noBinding, 543 r.mAllowStart_inBindService, 544 r.mAllowStart_byBindings, 545 FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, 546 false 547 ); 548 } 549 550 /** 551 * Logs an API event that occurred while no FGS was running. 552 * Only used to log API exit events 553 */ 554 @VisibleForTesting logFgsApiEventWithNoFgs(int uid, @FgsApiState int apiState, @ForegroundServiceApiType int apiType, long timestamp)555 public void logFgsApiEventWithNoFgs(int uid, 556 @FgsApiState int apiState, 557 @ForegroundServiceApiType int apiType, long timestamp) { 558 long apiDurationAfterFgsEnd = 0; 559 UidState uidState = mUids.get(uid); 560 if (uidState == null) { 561 return; 562 } 563 if (uidState.mLastFgsTimeStamp.contains(apiType)) { 564 apiDurationAfterFgsEnd = timestamp - uidState.mLastFgsTimeStamp.get(apiType); 565 } 566 final int[] apiTypes = new int[1]; 567 apiTypes[0] = apiType; 568 final long[] timeStamps = new long[1]; 569 timeStamps[0] = timestamp; 570 FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED, 571 uid, 572 null, 573 FGS_STATE_CHANGED_API_CALL, 574 false, // allowWhileInUsePermissionInFgs 575 0, // fgsStartReasonCode 576 0, 577 uid, 578 0, // callerTargetSdkVersion 579 0, 580 false, 581 false, 582 0, // durationMs 583 0, 584 0, 585 false, 586 0, 587 0, 588 false, 589 0, 590 0, 591 apiState, 592 apiTypes, 593 timeStamps, 594 ActivityManager.PROCESS_STATE_UNKNOWN, 595 ActivityManager.PROCESS_CAPABILITY_NONE, 596 ActivityManager.PROCESS_STATE_UNKNOWN, 597 ActivityManager.PROCESS_CAPABILITY_NONE, 598 0, 599 apiDurationAfterFgsEnd, 600 0, 601 0, 602 0, 603 0, 604 0, 605 0, 606 FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, 607 false 608 ); 609 } 610 611 /** 612 * Internal class for tracking open API calls 613 */ 614 private static class FgsApiRecord { 615 final int mUid; // the UID from where the API call came from 616 final int mPid; // the PID from where the API call came from 617 final String mPackageName; // the package name from where the API call came from 618 @ForegroundServiceApiType 619 int mType; // the type of API call (camera, etc) 620 boolean mIsAssociatedWithFgs; // is it associated with an FGS? 621 ServiceRecord mAssociatedFgsRecord; // the FGS it is associated with 622 final long mTimeStart; // timestamp for the event 623 FgsApiRecord(int uid, int pid, String packageName, @ForegroundServiceApiType int type, long timeStart)624 FgsApiRecord(int uid, 625 int pid, 626 String packageName, 627 @ForegroundServiceApiType int type, 628 long timeStart) { 629 this.mUid = uid; 630 this.mPid = pid; 631 this.mPackageName = packageName; 632 this.mType = type; 633 this.mTimeStart = timeStart; 634 } 635 } 636 } 637