Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the lifecycle for Android's StrictMode?

I'm trying to minimize the number of places in my code where I need to setup StrictMode. But I'm not sure if I'm right or not about the following.

The documentation for Android's StrictMode says you can use it for Applications, Activities and other components. I've read that it is not desirable to extend the Application class, and I'd prefer not to extend Application just to enable StrictMode. But I don't think I have to.

There are two policies you can use: ThreadPolicy (for a thread) and VmPolicy (for all threads). So it would seem that if I setup StrictMode on a thread once, it doesn't matter from where I do that, and violations will be reported thereafter on that thread regardless of other calls or not on StrictMode. I just need to call it from somewhere before violations could occur that I want to detect. And it needs to be setup for any new threads that get created in my application that I also want to check.

What I think I want to avoid is calling the build() methods more than I need to. Putting StrictMode at the beginning of onCreate() in all my activities means that build() is going to get called more than once on that thread. If I have one Launcher activity in my application, setting up StrictMode in that activity's onCreate() should be sufficient for the rest of the application. Is that true?

Secondly, if my main activity gets restarted even though the application did not die, is it technically necessary to call StrictMode again? Or is my thread still setup to report violations? I was thinking there might be some value in doing a wrapper-type of class around StrictMode like so:

public class MyStrictModeSettings {
    static private List<Long> setThreads = new ArrayList<Long>();

    // Prevent instantiation of this class
    private MyStrictModeSettings() {}

    static public synchronized void init() {
        try {
            Long tid = Thread.currentThread().getId();
            if(!setThreads.contains(tid)) {
                setThreads.add(tid);
                Class sMode = Class.forName("android.os.StrictMode");
                Method enableDefaults = sMode.getMethod("enableDefaults");
                enableDefaults.invoke(null);
            }
        }
        catch(Exception e) {
            // StrictMode not supported on this device, punt
            Log.v("StrictMode", "... not supported. Skipping...");
        }
    }
}

That way, in my main activity's onCreate(), I can simply call MyStrictModeSettings.init() and be done with it. And it should work on Android versions prior to 2.3 too. But it may not be worth it. Brad, are you there? Thanks.

Edit: Since VmPolicy is for all threads, technically I only need to set that up once per application, right? So enableDefaults() is wasting effort to redo the VmPolicy when it gets called a second, third, etc time? Again, maybe it's more trouble than it's worth to try to avoid the extra calls.

like image 749
Dave MacLean Avatar asked Jan 21 '23 17:01

Dave MacLean


2 Answers

Yes, VmPolicy is for the whole process so doing it once is fine. More times is cheap, though, so don't wory about it.

And yes, you only need to do it in your main/launcher activity's onCreate() --- that's the same "main" thread as all your other components.

like image 95
Brad Fitzpatrick Avatar answered Jan 23 '23 07:01

Brad Fitzpatrick


Looking at the source code, you can see that it is being called statically:

public static void setVmPolicy(final VmPolicy policy) {
    synchronized (StrictMode.class) {
        sVmPolicy = policy;
        sVmPolicyMask = policy.mask;
        setCloseGuardEnabled(vmClosableObjectLeaksEnabled());

        Looper looper = Looper.getMainLooper();
        if (looper != null) {
            MessageQueue mq = looper.mQueue;
            if (policy.classInstanceLimit.size() == 0 ||
                (sVmPolicyMask & VM_PENALTY_MASK) == 0) {
                mq.removeIdleHandler(sProcessIdleHandler);
                sIsIdlerRegistered = false;
            } else if (!sIsIdlerRegistered) {
                mq.addIdleHandler(sProcessIdleHandler);
                sIsIdlerRegistered = true;
            }
        }
    }
}

And the policy itself is also stored statically - there are no non-static member variables in the class.

    private static volatile VmPolicy sVmPolicy = VmPolicy.LAX;

This means you only need to do it once per application such as in the launch/entry activity for your application.

like image 24
RightHandedMonkey Avatar answered Jan 23 '23 08:01

RightHandedMonkey