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