Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: null pointer on get app context #1878

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -344,3 +344,25 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On
}
}
}

object ApplicationServiceUtil {
fun isValidInstance(_applicationService: IApplicationService?): Boolean {
return try {
if (_applicationService == null) {
println("Error: _applicationService is null")
false
} else if (_applicationService.appContext == null) {
println("Error: _applicationService.appContext is null")
false
} else {
true
}
} catch (e: NullPointerException) {
println("ApplicationService's AppContext not initialized: ${e.message}")
false
} catch (e: Exception) {
println("Exception thrown while checking ApplicationService's App Context: ${e.message}")
false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import android.os.Build
import com.onesignal.common.AndroidUtils
import com.onesignal.core.internal.application.IApplicationService
import com.onesignal.core.internal.device.IDeviceService
import com.onesignal.core.internal.application.impl.ApplicationServiceUtil

internal class DeviceService(private val _applicationService: IApplicationService) :
internal class DeviceService(private val _applicationService: IApplicationService?) :
IDeviceService {
companion object {
private const val HMS_CORE_SERVICES_PACKAGE = "com.huawei.hwid" // = HuaweiApiAvailability.SERVICES_PACKAGE
Expand Down Expand Up @@ -67,11 +68,13 @@ internal class DeviceService(private val _applicationService: IApplicationServic

// If running on Android O and targeting O we need version 26.0.0 for
// the new compat NotificationCompat.Builder constructor.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
AndroidUtils.getTargetSdkVersion(_applicationService.appContext) >= Build.VERSION_CODES.O
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!ApplicationServiceUtil.isValidInstance(_applicationService)) {
return IDeviceService.AndroidSupportLibraryStatus.MISSING
}

// Class was added in 26.0.0-beta2
if (!AndroidUtils.hasJobIntentService()) {
if (!AndroidUtils.hasJobIntentService() && AndroidUtils.getTargetSdkVersion(_applicationService!!.appContext) >= Build.VERSION_CODES.O) {
return IDeviceService.AndroidSupportLibraryStatus.OUTDATED
}
}
Expand Down Expand Up @@ -103,7 +106,11 @@ internal class DeviceService(private val _applicationService: IApplicationServic

private fun packageInstalledAndEnabled(packageName: String): Boolean {
return try {
val pm = _applicationService.appContext.packageManager
if (!ApplicationServiceUtil.isValidInstance(_applicationService)) {
return false;
}

val pm = _applicationService!!.appContext.packageManager
val info = pm.getPackageInfo(packageName, PackageManager.GET_META_DATA)
info.applicationInfo.enabled
} catch (e: PackageManager.NameNotFoundException) {
Expand Down Expand Up @@ -137,7 +144,11 @@ internal class DeviceService(private val _applicationService: IApplicationServic
val isHuaweiMobileServicesAvailableMethod = clazz.getMethod("isHuaweiMobileServicesAvailable", android.content.Context::class.java)
val availabilityInstance = newInstanceMethod.invoke(null)

val result = isHuaweiMobileServicesAvailableMethod.invoke(availabilityInstance, _applicationService.appContext) as Int
if (!ApplicationServiceUtil.isValidInstance(_applicationService)) {
return false;
}

val result = isHuaweiMobileServicesAvailableMethod.invoke(availabilityInstance, _applicationService!!.appContext) as Int

return result == HMS_AVAILABLE_SUCCESSFUL
} catch (e: ClassNotFoundException) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import android.content.SharedPreferences
import com.onesignal.common.threading.Waiter
import com.onesignal.core.internal.application.IApplicationService
import com.onesignal.core.internal.application.impl.ApplicationServiceUtil
import com.onesignal.core.internal.preferences.IPreferencesService
import com.onesignal.core.internal.preferences.PreferenceStores
import com.onesignal.core.internal.startup.IStartableService
Expand All @@ -17,7 +18,7 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.delay

internal class PreferencesService(
private val _applicationService: IApplicationService,
private val _applicationService: IApplicationService?,
private val _time: ITime,
) : IPreferencesService, IStartableService {
private val _prefsToApply: Map<String, MutableMap<String, Any?>> = mapOf(
Expand Down Expand Up @@ -154,7 +155,12 @@ internal class PreferencesService(

@Synchronized
private fun getSharedPrefsByName(store: String): SharedPreferences? {
return _applicationService.appContext.getSharedPreferences(store, Context.MODE_PRIVATE)

if (!ApplicationServiceUtil.isValidInstance(_applicationService)) {
return null
}

return _applicationService!!.appContext.getSharedPreferences(store, Context.MODE_PRIVATE)
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.onesignal.common.threading.suspendifyOnThread
import com.onesignal.core.CoreModule
import com.onesignal.core.internal.application.IApplicationService
import com.onesignal.core.internal.application.impl.ApplicationService
import com.onesignal.core.internal.application.impl.ApplicationServiceUtil
import com.onesignal.core.internal.config.ConfigModel
import com.onesignal.core.internal.config.ConfigModelStore
import com.onesignal.core.internal.operations.IOperationRepo
Expand Down Expand Up @@ -150,6 +151,9 @@ internal class OneSignalImp : IOneSignal, IServiceProvider {
val applicationService = _services.getService<IApplicationService>()
(applicationService as ApplicationService).start(context)

if (!ApplicationServiceUtil.isValidInstance(applicationService)) {
return false
}
// Give the logging singleton access to the application service to support visual logging.
Logging.applicationService = applicationService

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.onesignal.core.internal.application

import android.app.Activity
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import com.onesignal.core.internal.application.impl.ApplicationService
import com.onesignal.debug.LogLevel
import com.onesignal.debug.internal.logging.Logging
import com.onesignal.extensions.RobolectricTest
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.runner.junit4.KotestTestRunner
import org.junit.runner.RunWith
import com.onesignal.core.internal.application.impl.ApplicationServiceUtil

@RobolectricTest
@RunWith(KotestTestRunner::class)
class ApplicationServiceUtilsTests : FunSpec({

beforeAny {
Logging.logLevel = LogLevel.NONE
}

test("returns true if application service is not null and app context is not null") {
/* Given */
val context = ApplicationProvider.getApplicationContext<Context>()
val applicationService = ApplicationService()
applicationService.start(context)

/* When */
val result = ApplicationServiceUtil.isValidInstance(applicationService)

/* Then */
result shouldBe true
}

test("returns false if application service is null") {
/* Given */
val applicationService: IApplicationService? = null


/* When */
val result = ApplicationServiceUtil.isValidInstance(applicationService)

/* Then */
result shouldBe false
}

test("returns false if app context is null and or exception is thrown") {
/* Given */
val applicationService = ApplicationService()

/* When */
val result = ApplicationServiceUtil.isValidInstance(applicationService)

/* Then */
result shouldBe false
}

}) {
companion object {
fun pushActivity(applicationService: ApplicationService, currActivity: Activity, newActivity: Activity, destoryCurrent: Boolean = false) {
applicationService.onActivityPaused(currActivity)
applicationService.onActivityCreated(newActivity, null)
applicationService.onActivityStarted(newActivity)
applicationService.onActivityResumed(newActivity)
applicationService.onActivityStopped(currActivity)

if (destoryCurrent) {
applicationService.onActivityDestroyed(currActivity)
}
}

fun popActivity(applicationService: ApplicationService, currActivity: Activity, oldActivity: Activity) {
applicationService.onActivityPaused(currActivity)
applicationService.onActivityStarted(oldActivity)
applicationService.onActivityResumed(oldActivity)
applicationService.onActivityStopped(currActivity)
applicationService.onActivityDestroyed(currActivity)
}
}
}