Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

StrictMode: StrictModeDiskReadViolation when creating SharedPreference

I have a project with dagger setup with following provider method:

@Module(...)
abstract class AppModule {

  @Module
  companion object {
    ...
    @Provides
    @Singleton
    @JvmStatic
    fun provideSharedPreferences(@AppContext context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
  }

  @Binds
  @AppContext
  @Singleton
  abstract fun provideAppContext(application: Application): Context

}

And here's a code from application's onCreate():

override fun onCreate() {
  if (BuildConfig.DEBUG) {
    StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder()
        .detectAll()
        .penaltyLog()
        .penaltyDialog()
        .build())

    StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder()
        .detectAll()
        .penaltyLog()
        .build())

    Timber.plant(Timber.DebugTree())
  }
  ...
  super.onCreate()
}

Running the project on API 27 emulator results in following behavior:

With following logs:

D/StrictMode: StrictMode policy violation; ~duration=275 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=196671 violation=2 at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1440) at java.io.UnixFileSystem.checkAccess(UnixFileSystem.java:251) at java.io.File.exists(File.java:807) at android.app.ContextImpl.getDataDir(ContextImpl.java:2197) at android.app.ContextImpl.getPreferencesDir(ContextImpl.java:517) at android.app.ContextImpl.getSharedPreferencesPath(ContextImpl.java:714) at android.app.ContextImpl.getSharedPreferences(ContextImpl.java:368) at android.content.ContextWrapper.getSharedPreferences(ContextWrapper.java:167) at android.preference.PreferenceManager.getDefaultSharedPreferences(PreferenceManager.java:526) at com.some.package.di.module.AppModule$Companion.provideSharedPreferences(AppModule.kt:112) ...

What this means, is that following res.exists() reads from disk:

if (!res.exists() && android.os.Process.myUid() == android.os.Process.SYSTEM_UID) {
    Log.wtf(TAG, "Data directory doesn't exist for package " + getPackageName(),
            new Throwable());
}

And because that's happening on UI thread - StrictModeDiskReadViolation results.

Afaik, there does not exist an API to exclude some chunk of code (e.g. by package name) from StrictMode configuration. Practically, I'm ok to leave SharedPreferences related stuff to read from disk on UI thread.

I do not want to turn off read/write StrictMode rule because of this problem.

Question

What is the correct way to gracefully recover from this scenario?

like image 620
azizbekian Avatar asked Apr 15 '18 12:04

azizbekian


People also ask

What is strictmode in strict mode?

StrictMode. StrictMode is a developer tool which detects things you might be doing by accident and brings them to your attention so you can fix them. StrictMode is most commonly used to catch accidental disk or network access on the application's main thread, where UI operations are received and animations take place.

What are the methods available in the editor class for shared preferences?

Apart from the putString method , there are methods available in the editor class that allows manipulation of data inside shared preferences. They are listed as follows − It is an abstract method. It will commit your changes back from editor to the sharedPreference object you are calling

What is shared preferences in Android?

Android - Shared Preferences. Android provides many ways of storing data of an application. One of this way is called Shared Preferences. Shared Preferences allow you to save and retrieve data in the form of key,value pair.

Does strictmode affect the production build of the application?

Since the StrictMode is a developer tool, it runs only in development mode. It does not affect the production build in any way whatsoever. In order to identify and detect any problems within the application and show warning messages, StrictMode renders every component inside the application twice.


1 Answers

Afaik, there does not exist an API to exclude some chunk of code (e.g. by package name) from StrictMode configuration. Practically, I'm ok to leave SharedPreferences related stuff to read from disk on UI thread.

It does exist. StrictMode.allowThreadDiskReads() changes the permissions to allow for reads and returns the old ThreadPolicy so it can be reset once the read is done. This can then be used together with a "try-finally" setup to allow the read for a single action.

val oldPolicy = StrictMode.allowThreadDiskReads()
try {
    // Do reads here
} finally {
    StrictMode.setThreadPolicy(oldPolicy)
}

You could create a kotlin function that handles the restoration with a lambda:

fun <T> allowReads(block: () -> T): T {
    val oldPolicy = StrictMode.allowThreadDiskReads()
    try {
        return block()
    } finally {
        StrictMode.setThreadPolicy(oldPolicy)
    }
}
like image 98
Kiskae Avatar answered Nov 06 '22 17:11

Kiskae