Skip to content

Commit dc9e962

Browse files
committed
Make the Sessions test app more convenient to test (#7054)
Make the Sessions test app more convenient to test Initialize Firebase on the Application, not Activity, so it can be initialized in background services Fixed the process name for older Android API levels Made all the logcat tags be the same, so it will be easier to give test instructions like `tag:SessionsTestApp tag:FirebaseSessions` Added 2 background services with easy actions to interact with in the background, e.g., `am startservice -n com.google.firebase.testing.sessions/.MyServiceA -a PING`
1 parent d90ca97 commit dc9e962

File tree

9 files changed

+175
-35
lines changed

9 files changed

+175
-35
lines changed

firebase-sessions/test-app/src/main/AndroidManifest.xml

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@
4545

4646
<!-- Override value to 1.0 to always have a fireperf verbose session -->
4747
<meta-data
48-
android:name="sessions_sampling_percentage"
49-
android:value="0.01" />
48+
android:name="sessions_sampling_percentage"
49+
android:value="0.01" />
5050

5151
<meta-data
5252
android:name="firebase_performance_logcat_enabled"
@@ -74,6 +74,18 @@
7474
android:resource="@xml/homescreen_widget" />
7575
</receiver>
7676

77+
<service
78+
android:exported="true"
79+
android:name=".MyServiceA"
80+
android:process=":a"
81+
tools:ignore="ExportedService" />
82+
83+
<service
84+
android:exported="true"
85+
android:name=".MyServiceB"
86+
android:process=":b"
87+
tools:ignore="ExportedService" />
88+
7789
<service
7890
android:enabled="true"
7991
android:exported="false"

firebase-sessions/test-app/src/main/kotlin/com/google/firebase/testing/sessions/BaseActivity.kt

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,48 +18,47 @@ package com.google.firebase.testing.sessions
1818

1919
import android.app.ActivityManager
2020
import android.app.ActivityManager.RunningAppProcessInfo
21-
import android.app.Application
22-
import android.os.Build
2321
import android.os.Bundle
2422
import android.util.Log
2523
import androidx.appcompat.app.AppCompatActivity
2624
import com.google.firebase.FirebaseApp
2725
import com.google.firebase.perf.FirebasePerformance
26+
import com.google.firebase.testing.sessions.TestApplication.Companion.TAG
27+
import com.google.firebase.testing.sessions.TestApplication.Companion.myProcessName
2828

2929
open class BaseActivity : AppCompatActivity() {
3030

3131
override fun onCreate(savedInstanceState: Bundle?) {
3232
super.onCreate(savedInstanceState)
33-
FirebaseApp.initializeApp(this)
3433
setProcessAttribute()
3534
logProcessDetails()
3635
logFirebaseDetails()
37-
Log.i(TAG, "onCreate - ${getProcessName()} - ${getImportance()}")
36+
Log.i(TAG, "onCreate - $myProcessName - ${getImportance()}")
3837
}
3938

4039
override fun onPause() {
4140
super.onPause()
42-
Log.i(TAG, "onPause - ${getProcessName()} - ${getImportance()}")
41+
Log.i(TAG, "onPause - $myProcessName - ${getImportance()}")
4342
}
4443

4544
override fun onStop() {
4645
super.onStop()
47-
Log.i(TAG, "onStop - ${getProcessName()} - ${getImportance()}")
46+
Log.i(TAG, "onStop - $myProcessName - ${getImportance()}")
4847
}
4948

5049
override fun onResume() {
5150
super.onResume()
52-
Log.i(TAG, "onResume - ${getProcessName()} - ${getImportance()}")
51+
Log.i(TAG, "onResume - $myProcessName - ${getImportance()}")
5352
}
5453

5554
override fun onStart() {
5655
super.onStart()
57-
Log.i(TAG, "onStart - ${getProcessName()} - ${getImportance()}")
56+
Log.i(TAG, "onStart - $myProcessName - ${getImportance()}")
5857
}
5958

6059
override fun onDestroy() {
6160
super.onDestroy()
62-
Log.i(TAG, "onDestroy - ${getProcessName()} - ${getImportance()}")
61+
Log.i(TAG, "onDestroy - $myProcessName - ${getImportance()}")
6362
}
6463

6564
private fun getImportance(): Int {
@@ -68,15 +67,11 @@ open class BaseActivity : AppCompatActivity() {
6867
return processInfo.importance
6968
}
7069

71-
protected fun getProcessName(): String =
72-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) Application.getProcessName() else "unknown"
73-
7470
private fun logProcessDetails() {
7571
val pid = android.os.Process.myPid()
7672
val uid = android.os.Process.myUid()
7773
val activity = javaClass.name
78-
val process = getProcessName()
79-
Log.i(TAG, "activity: $activity process: $process, pid: $pid, uid: $uid")
74+
Log.i(TAG, "activity: $activity process: $myProcessName, pid: $pid, uid: $uid")
8075
}
8176

8277
private fun logFirebaseDetails() {
@@ -85,15 +80,11 @@ open class BaseActivity : AppCompatActivity() {
8580
val defaultFirebaseApp = FirebaseApp.getInstance()
8681
Log.i(
8782
TAG,
88-
"activity: $activity firebase: ${defaultFirebaseApp.name} appsCount: ${firebaseApps.count()}"
83+
"activity: $activity firebase: ${defaultFirebaseApp.name} appsCount: ${firebaseApps.count()}",
8984
)
9085
}
9186

9287
private fun setProcessAttribute() {
93-
FirebasePerformance.getInstance().putAttribute("process_name", getProcessName())
94-
}
95-
96-
companion object {
97-
val TAG = "BaseActivity"
88+
FirebasePerformance.getInstance().putAttribute("process_name", myProcessName)
9889
}
9990
}

firebase-sessions/test-app/src/main/kotlin/com/google/firebase/testing/sessions/CrashBroadcastReceiver.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import android.content.Context
2121
import android.content.Intent
2222
import android.util.Log
2323
import android.widget.Toast
24+
import com.google.firebase.testing.sessions.TestApplication.Companion.TAG
2425

2526
class CrashBroadcastReceiver : BroadcastReceiver() {
2627

@@ -42,7 +43,6 @@ class CrashBroadcastReceiver : BroadcastReceiver() {
4243
}
4344

4445
companion object {
45-
val TAG = "CrashBroadcastReceiver"
4646
val CRASH_ACTION = "com.google.firebase.testing.sessions.CrashBroadcastReceiver.CRASH_ACTION"
4747
val TOAST_ACTION = "com.google.firebase.testing.sessions.CrashBroadcastReceiver.TOAST_ACTION"
4848
}

firebase-sessions/test-app/src/main/kotlin/com/google/firebase/testing/sessions/FirstFragment.kt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package com.google.firebase.testing.sessions
1818

19-
import android.app.Application
2019
import android.content.Intent
2120
import android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT
2221
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
@@ -31,6 +30,7 @@ import androidx.lifecycle.lifecycleScope
3130
import com.google.firebase.crashlytics.FirebaseCrashlytics
3231
import com.google.firebase.perf.FirebasePerformance
3332
import com.google.firebase.perf.trace
33+
import com.google.firebase.testing.sessions.TestApplication.Companion.myProcessName
3434
import com.google.firebase.testing.sessions.databinding.FragmentFirstBinding
3535
import java.net.HttpURLConnection
3636
import java.net.URL
@@ -129,7 +129,7 @@ class FirstFragment : Fragment() {
129129
intent.addFlags(FLAG_ACTIVITY_NEW_TASK)
130130
startActivity(intent)
131131
}
132-
binding.processName.text = getProcessName()
132+
binding.processName.text = myProcessName
133133
}
134134

135135
override fun onResume() {
@@ -152,9 +152,5 @@ class FirstFragment : Fragment() {
152152
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
153153
SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(Date())
154154
else "unknown"
155-
156-
fun getProcessName(): String =
157-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) Application.getProcessName()
158-
else "unknown"
159155
}
160156
}

firebase-sessions/test-app/src/main/kotlin/com/google/firebase/testing/sessions/ForegroundService.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import android.util.Log
2929
import androidx.core.app.NotificationCompat
3030
import androidx.core.content.ContextCompat
3131
import com.google.firebase.FirebaseApp
32+
import com.google.firebase.testing.sessions.TestApplication.Companion.TAG
3233

3334
class ForegroundService : Service() {
3435
private val CHANNEL_ID = "CrashForegroundService"
@@ -104,18 +105,16 @@ class ForegroundService : Service() {
104105
}
105106

106107
companion object {
107-
val TAG = "WidgetForegroundService"
108-
109108
fun startService(context: Context, message: String) {
110-
Log.i(TAG, "Starting foreground serice")
109+
Log.i(TAG, "Starting foreground service")
111110
ContextCompat.startForegroundService(
112111
context,
113112
Intent(context, ForegroundService::class.java).putExtra("inputExtra", message),
114113
)
115114
}
116115

117116
fun stopService(context: Context) {
118-
Log.i(TAG, "Stopping serice")
117+
Log.i(TAG, "Stopping service")
119118
context.stopService(Intent(context, ForegroundService::class.java))
120119
}
121120
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2025 Google LLC
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.google.firebase.testing.sessions
18+
19+
import android.app.Service
20+
import android.content.Intent
21+
import android.os.IBinder
22+
import android.util.Log
23+
import com.google.firebase.testing.sessions.TestApplication.Companion.TAG
24+
import com.google.firebase.testing.sessions.TestApplication.Companion.myProcessName
25+
import kotlin.system.exitProcess
26+
27+
class MyServiceA : Service() {
28+
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
29+
Log.i(TAG, "Service A action: ${intent?.action} on process: $myProcessName")
30+
31+
// Send actions from adb shell this way, so it can start the process if needed:
32+
// am startservice -n com.google.firebase.testing.sessions/.MyServiceA -a PING
33+
when (intent?.action) {
34+
"PING" -> ping()
35+
"CRASH" -> crash()
36+
"KILL" -> kill()
37+
"SESSION" -> session()
38+
}
39+
40+
return START_STICKY
41+
}
42+
43+
private fun ping() {
44+
repeat(7) { Log.i(TAG, "*** pong ***") }
45+
}
46+
47+
private fun crash() {
48+
Log.i(TAG, "crashing")
49+
throw IndexOutOfBoundsException("crash service a")
50+
}
51+
52+
private fun kill() {
53+
Log.i(TAG, "killing process $myProcessName")
54+
exitProcess(0)
55+
}
56+
57+
private fun session() {
58+
Log.i(
59+
TAG,
60+
"service a, session id: ${TestApplication.sessionSubscriber.sessionDetails?.sessionId}",
61+
)
62+
}
63+
64+
override fun onBind(intent: Intent?): IBinder? = null
65+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2025 Google LLC
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.google.firebase.testing.sessions
18+
19+
import android.app.Service
20+
import android.content.Intent
21+
import android.os.IBinder
22+
import android.util.Log
23+
import com.google.firebase.testing.sessions.TestApplication.Companion.TAG
24+
import com.google.firebase.testing.sessions.TestApplication.Companion.myProcessName
25+
import kotlin.system.exitProcess
26+
27+
class MyServiceB : Service() {
28+
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
29+
Log.i(TAG, "Service B action: ${intent?.action} on process: $myProcessName")
30+
31+
when (intent?.action) {
32+
"PING" -> ping()
33+
"CRASH" -> crash()
34+
"KILL" -> kill()
35+
}
36+
37+
return START_STICKY
38+
}
39+
40+
private fun ping() {
41+
repeat(7) { Log.i(TAG, "*** hello ***") }
42+
Log.i(TAG, "session id: ${TestApplication.sessionSubscriber.sessionDetails?.sessionId}")
43+
}
44+
45+
private fun crash() {
46+
Log.i(TAG, "crashing")
47+
throw IllegalStateException("crash in service b")
48+
}
49+
50+
private fun kill() {
51+
Log.i(TAG, "killing process $myProcessName")
52+
exitProcess(0)
53+
}
54+
55+
override fun onBind(intent: Intent?): IBinder? = null
56+
}

firebase-sessions/test-app/src/main/kotlin/com/google/firebase/testing/sessions/SecondActivity.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import android.widget.Button
2525
import android.widget.TextView
2626
import androidx.lifecycle.lifecycleScope
2727
import com.google.firebase.perf.FirebasePerformance
28+
import com.google.firebase.testing.sessions.TestApplication.Companion.myProcessName
2829
import kotlinx.coroutines.delay
2930
import kotlinx.coroutines.launch
3031

@@ -56,7 +57,7 @@ class SecondActivity : BaseActivity() {
5657
.killBackgroundProcesses("com.google.firebase.testing.sessions")
5758
}
5859
}
59-
findViewById<TextView>(R.id.process_name_second).text = getProcessName()
60+
findViewById<TextView>(R.id.process_name_second).text = myProcessName
6061
}
6162

6263
override fun onResume() {

0 commit comments

Comments
 (0)