StrictMode for lower platform versions
Asked Answered
B

6

12

I have started using the Android StrictMode and find that it would be great to have it always running during development and not just on a special branch I created in git. The reason I did this is my apps requirement to run with 1.6 and up.

I read on the android developer blog that you can set it up so that you activate it via reflection. I was just wondering how that would actually look like and if it might be possible to have this documented here (or somewhere else) rather than having everybody that wants to use it work out themselves.

Belfort answered 6/1, 2011 at 0:19 Comment(1)
if I dont get an answer here I will figure it out myself when I have a bit of time to do it.. need to prep for andevcon at the moment though..Belfort
B
8

So I did not want to wait and decided to make the effort and implement this myself. It basically boils down to wrapping StrictMode in a wrapper class and deciding at runtime via reflection if we can activate it.

I have documented it in detail in a blog post and made it available in github.

Belfort answered 7/1, 2011 at 8:0 Comment(2)
@bla ... kindly remove your downvote.. I fixed the link .. this is 5 years old. Things move around..Belfort
Thanks Manfred; a downvote is generally an efficient way to get links fixed ;). One should check for MorseFlashApplication and StrictModeWrapper classes.Subscribe
F
9

I've read Manfred's blog post but it doesn't work if you set target platform version lower than 2.3 because StrictMode.enableDefaults(); method is unavailable.

Here is my solution that relies fully on reflection and doesn't generate compilation errors:

    try {
        Class<?> strictModeClass = Class.forName("android.os.StrictMode", true, Thread.currentThread()
                .getContextClassLoader());

        Class<?> threadPolicyClass = Class.forName("android.os.StrictMode$ThreadPolicy", true, Thread
                .currentThread().getContextClassLoader());

        Class<?> threadPolicyBuilderClass = Class.forName("android.os.StrictMode$ThreadPolicy$Builder", true,
                Thread.currentThread().getContextClassLoader());

        Method setThreadPolicyMethod = strictModeClass.getMethod("setThreadPolicy", threadPolicyClass);

        Method detectAllMethod = threadPolicyBuilderClass.getMethod("detectAll");
        Method penaltyMethod = threadPolicyBuilderClass.getMethod("penaltyLog");
        Method buildMethod = threadPolicyBuilderClass.getMethod("build");

        Constructor<?> threadPolicyBuilderConstructor = threadPolicyBuilderClass.getConstructor();
        Object threadPolicyBuilderObject = threadPolicyBuilderConstructor.newInstance();

        Object obj = detectAllMethod.invoke(threadPolicyBuilderObject);

        obj = penaltyMethod.invoke(obj);
        Object threadPolicyObject = buildMethod.invoke(obj);
        setThreadPolicyMethod.invoke(strictModeClass, threadPolicyObject);

    } catch (Exception ex) {
        Log.w(TAG, ex);
    }
Floodlight answered 15/11, 2011 at 15:4 Comment(2)
The implementation is in github and has been tested and used by many people. It works just fine. I use it every day. But yes... if you need target below 2.3 your trick will work as well.Belfort
@ManfredMoser The only reason I posted it is need to support targets lower than 2.3. Your solution is good, but in this special case it doesn't work.Floodlight
B
8

So I did not want to wait and decided to make the effort and implement this myself. It basically boils down to wrapping StrictMode in a wrapper class and deciding at runtime via reflection if we can activate it.

I have documented it in detail in a blog post and made it available in github.

Belfort answered 7/1, 2011 at 8:0 Comment(2)
@bla ... kindly remove your downvote.. I fixed the link .. this is 5 years old. Things move around..Belfort
Thanks Manfred; a downvote is generally an efficient way to get links fixed ;). One should check for MorseFlashApplication and StrictModeWrapper classes.Subscribe
M
7

I saw your blog post. Since you only ever want to setup StrictMode at most once per Java file, would it make any sense to simplify the code to call for setup as follows?

Here's an alternate StrictModeWrapper:

import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.os.StrictMode;

public class StrictModeWrapper {
    public static void init(Context context) {
        // check if android:debuggable is set to true
        int applicationFlags = context.getApplicationInfo().flags;
        if ((applicationFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .detectDiskReads()
                .detectDiskWrites()
                .detectNetwork()
                .penaltyLog()
                .build());
            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                .detectLeakedSqlLiteObjects()
                .penaltyLog()
                .penaltyDeath()
                .build());
        }
    }
}

From your code, you only need to do the following:

try {
    StrictModeWrapper.init(this);
}
catch(Throwable throwable) {
    Log.v("StrictMode", "... is not available. Punting...");
}

where this is the local context, such as your Activity or Application or whatever. This seems to work for pre-2.3 Android, and also gives you the power of using the other methods of the Builder classes to configure StrictMode exactly as you'd like.

Mirnamirror answered 18/1, 2011 at 3:45 Comment(3)
Yes.. that would work too and might be a bit shorter in the sense that it does not even try to use reflection but just does a full on init. It is a bit less flexible this way though. It is however true that you only want to do this all once. I just do it in the onCreate of the application class, which is a singleton already anyway..Belfort
I once saw an answer from Dianne Hackborn on the Android Developers group that recommended against extending Application if it's not absolutely necessary. The policies apply to threads, so you could initialize StrictMode in the onCreate() of your launcher activity, and it should then be just as good as initializing from Application as it would apply to the main thread. Unless of course you fire up additional threads that you want to monitor, but you'd need to setup StrictMode on those threads as well even if you initialized from Application.Mirnamirror
Yes. Thats another possibility. I also saw that recommendation from Dianne, but MANY apps I see extends application and it works quite well that way. Like they say .. there are many ways to skin a cat ;-)Belfort
T
1

I've thrown together another variation on the theme above, which I've outlined in a blog post here. The main difference in my approach is that it also provides wrappers for the disk and vm policy objects, so that you easily can bracket StrictMode-offending code with temporary policy changes. Feedback is welcome.

Teufert answered 26/9, 2011 at 18:31 Comment(0)
C
1

To Pixel code I also added this (based on StrictMode Android API example):

            // VM policy
            Class<?> VmPolicyClass = Class.forName("android.os.StrictMode$VmPolicy", true, Thread.currentThread().getContextClassLoader());

            Class<?> VmPolicyBuilderClass = Class.forName("android.os.StrictMode$VmPolicy$Builder", true, Thread.currentThread().getContextClassLoader());

            Method setVmPolicyMethod = strictModeClass.getMethod("setVmPolicy", VmPolicyClass);

            Method detectLeakedSqlLiteObjectsMethod = VmPolicyBuilderClass.getMethod("detectLeakedSqlLiteObjects");
            Method detectLeakedClosableObjectsMethod = null; 
            try
            {
                detectLeakedClosableObjectsMethod = VmPolicyBuilderClass.getMethod("detectLeakedClosableObjects");
            }
            catch (Exception e) {}
            Method penaltyLogMethod = VmPolicyBuilderClass.getMethod("penaltyLog");
            Method penaltyDeathMethod = VmPolicyBuilderClass.getMethod("penaltyDeath");
            Method VmbuildMethod = VmPolicyBuilderClass.getMethod("build");

            Constructor<?> VmPolicyBuilderConstructor = VmPolicyBuilderClass.getConstructor();
            Object VmPolicyBuilderObject = VmPolicyBuilderConstructor.newInstance();

            Object Vmobj = detectLeakedSqlLiteObjectsMethod.invoke(VmPolicyBuilderObject);
            if (detectLeakedClosableObjectsMethod != null) Vmobj = detectLeakedClosableObjectsMethod.invoke(Vmobj);
            Vmobj = penaltyLogMethod.invoke(Vmobj);
            Vmobj = penaltyDeathMethod.invoke(Vmobj);

            Object VmPolicyObject = VmbuildMethod.invoke(Vmobj);
            setVmPolicyMethod.invoke(strictModeClass, VmPolicyObject);
Corrinnecorrival answered 31/7, 2012 at 20:35 Comment(0)
M
0

Set the Android Manifest to something like this.

< uses-sdk android:minSdkVersion="8" android:targetSdkVersion="16" android:maxSdkVersion="16"/ >

use the below code in onCreate Method.

int SDK_INT = android.os.Build.VERSION.SDK_INT;

} if (SDK_INT>8){

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();

StrictMode.setThreadPolicy(policy);

}

Note: Disable the warning as you are already checking which version of the Android is going to use this code.

this Code will be activated if the Android version is higher than Android 2.2

Manteau answered 4/9, 2012 at 14:55 Comment(5)
This will not work on older Android versions since it assumes the class StrictMode is available.. which is not the case.Belfort
I am using this on my Android 2.2 with new application Popup Facebook, For this you have to choose target as stated above in the post there will be error in the logcat if the android version is lower than 2.3 but that would be about stating that there is a dead code.Manteau
thats true but as far as the above code is concerned it should work theoretically, I have not tried for 1.1 but yes for sure it would work for Android 2.1 and above.Manteau
@ManfredMoser I have not tried on Android 1.1 as i dont have the sdk for android 1.1 but yet i have tried on Android SDK 1.5. have you tired the code with 1.1? Please let me know if you have tried it so that i can edit my answer accordingly.Manteau
It works for me below 2.3. The dalvik will log an error stating that he cannot find the class StrictMode but the app won't crash. It would only crash if we would try to use the StrictMode class and enter the IF branch - but we don't do that. Ergo, the snippet WORKS.Fugere

© 2022 - 2024 — McMap. All rights reserved.