diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/metrics/AppStartTrace.java b/firebase-perf/src/main/java/com/google/firebase/perf/metrics/AppStartTrace.java index 7574f989d92..bec5f8df82f 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/metrics/AppStartTrace.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/metrics/AppStartTrace.java @@ -14,6 +14,8 @@ package com.google.firebase.perf.metrics; +import static com.google.firebase.perf.util.AppProcessesProvider.getAppProcesses; + import android.annotation.SuppressLint; import android.app.Activity; import android.app.ActivityManager; @@ -509,17 +511,10 @@ public static boolean isAnyAppProcessInForeground(Context appContext) { if (activityManager == null) { return true; } - List appProcesses = - activityManager.getRunningAppProcesses(); - if (appProcesses != null) { - String appProcessName = appContext.getPackageName(); - String allowedAppProcessNamePrefix = appProcessName + ":"; + List appProcesses = getAppProcesses(appContext); + if (!appProcesses.isEmpty()) { for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) { - if (appProcess.importance != ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { - continue; - } - if (appProcess.processName.equals(appProcessName) - || appProcess.processName.startsWith(allowedAppProcessNamePrefix)) { + if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { boolean isAppInForeground = true; // For the case when the app is in foreground and the device transitions to sleep mode, diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/transport/TransportManager.java b/firebase-perf/src/main/java/com/google/firebase/perf/transport/TransportManager.java index 6bfb3c9ef2c..54d5b0792c3 100644 --- a/firebase-perf/src/main/java/com/google/firebase/perf/transport/TransportManager.java +++ b/firebase-perf/src/main/java/com/google/firebase/perf/transport/TransportManager.java @@ -14,7 +14,7 @@ package com.google.firebase.perf.transport; -import static com.google.firebase.sessions.ProcessDetailsProvider.getProcessDetailsProvider; +import static com.google.firebase.perf.util.AppProcessesProvider.getProcessName; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MINUTES; @@ -231,8 +231,7 @@ private void finishInitialization() { applicationInfoBuilder = ApplicationInfo.newBuilder(); applicationInfoBuilder .setGoogleAppId(firebaseApp.getOptions().getApplicationId()) - .setProcessName( - getProcessDetailsProvider().getCurrentProcessDetails(appContext).getProcessName()) + .setProcessName(getProcessName(appContext)) .setAndroidAppInfo( AndroidApplicationInfo.newBuilder() .setPackageName(packageName) diff --git a/firebase-perf/src/main/java/com/google/firebase/perf/util/AppProcessesProvider.kt b/firebase-perf/src/main/java/com/google/firebase/perf/util/AppProcessesProvider.kt new file mode 100644 index 00000000000..c4d820f31e3 --- /dev/null +++ b/firebase-perf/src/main/java/com/google/firebase/perf/util/AppProcessesProvider.kt @@ -0,0 +1,73 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.firebase.perf.util + +import android.app.ActivityManager +import android.app.Application +import android.content.Context +import android.os.Build +import android.os.Process +import com.google.android.gms.common.util.ProcessUtils + +/** + * A singleton that contains helper functions to get relevant process details. TODO(b/418041083): + * Explore using a common utility. See [com.google.firebase.sessions.ProcessDetailsProvider]. + */ +object AppProcessesProvider { + /** Gets the details for all of this app's running processes. */ + @JvmStatic + fun getAppProcesses(context: Context): List { + val appUid = context.applicationInfo.uid + val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager + val runningAppProcesses = activityManager?.runningAppProcesses ?: listOf() + + return runningAppProcesses.filterNotNull().filter { + // Only collect process info for this app's processes. + it.uid == appUid + } + } + + /** + * Gets this app's current process name. + * + * If the current process details are not found for whatever reason, returns an empty string. + */ + @JvmStatic + fun getProcessName(context: Context): String { + val pid = Process.myPid() + return getAppProcesses(context).find { it.pid == pid }?.processName ?: getProcessName() + } + + /** Gets the app's current process name. If it could not be found, return the default. */ + private fun getProcessName(default: String = ""): String { + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU) { + return Process.myProcessName() + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + Application.getProcessName()?.let { + return it + } + } + + // GMS core has different ways to get the process name on old api levels. + ProcessUtils.getMyProcessName()?.let { + return it + } + + // Returns default if nothing works. + return default + } +} diff --git a/firebase-sessions/src/main/kotlin/com/google/firebase/sessions/ProcessDetailsProvider.kt b/firebase-sessions/src/main/kotlin/com/google/firebase/sessions/ProcessDetailsProvider.kt index 9a86a997513..65d1dfbbc60 100644 --- a/firebase-sessions/src/main/kotlin/com/google/firebase/sessions/ProcessDetailsProvider.kt +++ b/firebase-sessions/src/main/kotlin/com/google/firebase/sessions/ProcessDetailsProvider.kt @@ -28,11 +28,7 @@ import com.google.android.gms.common.util.ProcessUtils * * @hide */ -object ProcessDetailsProvider { - @JvmStatic - fun getProcessDetailsProvider(): ProcessDetailsProvider { - return this - } +internal object ProcessDetailsProvider { /** Gets the details for all of this app's running processes. */ fun getAppProcessDetails(context: Context): List { val appUid = context.applicationInfo.uid diff --git a/firebase-sessions/src/main/kotlin/com/google/firebase/sessions/SessionEvent.kt b/firebase-sessions/src/main/kotlin/com/google/firebase/sessions/SessionEvent.kt index 0e37dcddadd..c9eff6684f6 100644 --- a/firebase-sessions/src/main/kotlin/com/google/firebase/sessions/SessionEvent.kt +++ b/firebase-sessions/src/main/kotlin/com/google/firebase/sessions/SessionEvent.kt @@ -81,7 +81,7 @@ internal data class DataCollectionStatus( ) /** Container for information about the process */ -data class ProcessDetails( +internal data class ProcessDetails( val processName: String, val pid: Int, val importance: Int,