Skip to content

Commit 572432b

Browse files
fix: Ensure that the app is initialized or otherwise don't use its modules. (#2143)
Apart form the main path, whne the user opens the app manually, the app can be initialized via intents, handled by services and receivers, such as `FCMHandlerService` and `OnBootAndUpdateBroadcastReceiver`. The app should be initialized form them before any action can be taken as the result of receiving the intent. However, sometime the initialization is not possible and in such cases the receiver should log a message and close gracefully, without crashing.
1 parent 431b65c commit 572432b

File tree

3 files changed

+56
-41
lines changed

3 files changed

+56
-41
lines changed

app/src/main/scala/com/waz/services/fcm/FCMHandlerService.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,9 @@ class FCMHandlerService extends FirebaseMessagingService with ZMessagingService
5858
* According to the docs, we have 10 seconds to process notifications upon receiving the `remoteMessage`.
5959
* it is sometimes not enough time to process everything - leading to missing messages!
6060
*/
61-
override def onMessageReceived(remoteMessage: RemoteMessage) = {
61+
override def onMessageReceived(remoteMessage: RemoteMessage) = if (WireApplication.ensureInitialized()){
6262
import FCMHandlerService._
6363

64-
WireApplication.APP_INSTANCE.ensureInitialized()
65-
6664
Option(remoteMessage.getData).map(_.asScala.toMap).foreach { data =>
6765
verbose(l"onMessageReceived with data: ${redactedString(data.toString())}")
6866
Option(ZMessaging.currentGlobal) match {

app/src/main/scala/com/waz/services/websocket/WebSocketService.scala

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import android.content
2323
import android.content.{BroadcastReceiver, Context, Intent}
2424
import android.os.{Build, IBinder}
2525
import android.support.v4.app.NotificationCompat
26+
import android.util.Log
2627
import com.waz.content.GlobalPreferences.{PushEnabledKey, WsForegroundKey}
2728
import com.waz.jobs.PushTokenCheckJob
2829
import com.waz.log.BasicLogging.LogTag.DerivedLogTag
@@ -81,46 +82,47 @@ class WebSocketController(implicit inj: Injector) extends Injectable {
8182
*/
8283
class OnBootAndUpdateBroadcastReceiver extends BroadcastReceiver with DerivedLogTag {
8384

84-
private var context: Context = _
85+
private val TAG = this.getClass.getName
8586

86-
implicit lazy val injector: Injector =
87-
context.getApplicationContext.asInstanceOf[WireApplication].module
87+
private var context: Context = _
8888

8989
override def onReceive(context: Context, intent: Intent): Unit = {
9090
this.context = context
91-
verbose(l"onReceive ${RichIntent(intent)}")
92-
93-
WireApplication.APP_INSTANCE.ensureInitialized()
94-
95-
injector.binding[AccountsService] match {
96-
case Some(accounts) =>
97-
verbose(l"AccountsService loaded")
98-
accounts().zmsInstances.head.foreach { zs =>
99-
zs.map(_.selfUserId).foreach(PushTokenCheckJob(_))
100-
} (Threading.Background)
101-
102-
case _ =>
103-
error(l"Failed to load AccountsService")
104-
}
105-
106-
injector.binding[WebSocketController] match {
107-
case Some(controller) =>
108-
verbose(l"WebSocketController loaded")
109-
controller().serviceInForeground.head.foreach {
110-
case true =>
111-
verbose(l"startForegroundService")
112-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
113-
context.startForegroundService(new Intent(context, classOf[WebSocketService]))
114-
else
115-
WebSocketService(context)
116-
case false =>
117-
verbose(l"foreground service not needed, will wait for application to start service if necessary")
118-
} (Threading.Ui)
91+
Log.i(TAG, s"onReceive ${intent.getDataString}")
92+
93+
if (WireApplication.ensureInitialized())
94+
Option(context.getApplicationContext.asInstanceOf[WireApplication].module).foreach { injector =>
95+
injector.binding[AccountsService] match {
96+
case Some(accounts) =>
97+
Log.i(TAG, "AccountsService loaded")
98+
accounts().zmsInstances.head.foreach { zs =>
99+
zs.map(_.selfUserId).foreach(PushTokenCheckJob(_))
100+
}(Threading.Background)
101+
102+
case _ =>
103+
Log.e(TAG, "Failed to load AccountsService")
104+
}
119105

120-
case None =>
121-
error(l"Failed to load WebSocketController")
122-
}
106+
injector.binding[WebSocketController] match {
107+
case Some(controller) =>
108+
Log.i(TAG, s"WebSocketController loaded")
109+
controller().serviceInForeground.head.foreach {
110+
case true =>
111+
Log.i(TAG, s"startForegroundService")
112+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
113+
context.startForegroundService(new Intent(context, classOf[WebSocketService]))
114+
else
115+
WebSocketService(context)
116+
case false =>
117+
Log.i(TAG, s"foreground service not needed, will wait for application to start service if necessary")
118+
}(Threading.Ui)
119+
120+
case None =>
121+
Log.e(TAG, s"Failed to load WebSocketController")
122+
}
123+
}
123124
}
125+
124126
}
125127

126128

app/src/main/scala/com/waz/zclient/WireApplication.scala

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import android.renderscript.RenderScript
2929
import android.support.multidex.MultiDexApplication
3030
import android.support.v4.app.{FragmentActivity, FragmentManager}
3131
import android.telephony.TelephonyManager
32+
import android.util.Log
3233
import com.evernote.android.job.{JobCreator, JobManager}
3334
import com.google.android.gms.security.ProviderInstaller
3435
import com.waz.api.NetworkMode
@@ -97,6 +98,10 @@ import scala.util.control.NonFatal
9798
object WireApplication extends DerivedLogTag {
9899
var APP_INSTANCE: WireApplication = _
99100

101+
def ensureInitialized(): Boolean =
102+
if (Option(APP_INSTANCE).isEmpty) false // too early
103+
else APP_INSTANCE.ensureInitialized()
104+
100105
type AccountToImageLoader = (UserId) => Future[Option[ImageLoader]]
101106
type AccountToAssetsStorage = (UserId) => Future[Option[AssetsStorage]]
102107
type AccountToUsersStorage = (UserId) => Future[Option[UsersStorage]]
@@ -370,11 +375,21 @@ class WireApplication extends MultiDexApplication with WireContext with Injectab
370375
ensureInitialized()
371376
}
372377

373-
def ensureInitialized(): Unit =
374-
if (Option(ZMessaging.currentGlobal).isEmpty)
375-
inject[BackendController].getStoredBackendConfig.foreach(ensureInitialized)
378+
private[waz] def ensureInitialized(): Boolean =
379+
if (Option(ZMessaging.currentGlobal).isDefined) true // the app is initialized, nothing to do here
380+
else
381+
try {
382+
inject[BackendController].getStoredBackendConfig.fold(false){ config =>
383+
ensureInitialized(config)
384+
true
385+
}
386+
} catch {
387+
case t: Throwable =>
388+
Log.e(WireApplication.getClass.getName, "Failed to initialize the app", t)
389+
false
390+
}
376391

377-
def ensureInitialized(backend: BackendConfig) = {
392+
def ensureInitialized(backend: BackendConfig): Unit = {
378393
JobManager.create(this).addJobCreator(new JobCreator {
379394
override def create(tag: String) =
380395
if (tag.contains(FetchJob.Tag)) new FetchJob

0 commit comments

Comments
 (0)