Android StrictMode 检测

来源:互联网 发布:遗传算法理解 编辑:程序博客网 时间:2024/05/21 18:48

 StrictMode是Android为了提高性能,当在主线程进行了IO、网络等操作是,进行的严格模式检测。StrictMode有两两种级别的policy检测,Thread和dalvikvm,开启方式如下:

    Thread policy:
          strictmode.setthreadpolicy(new  strictmode.threadpolicy.builder()
                  .detectdiskreads()
                  .detectdiskwrites()
                  .detectnetwork()   // or .detectall() for all detectable problems
                  .penaltylog()
                  .build());

    dalvikvm policy:
          StrictMode.setVmPolicy(new {@link VmPolicy.Builder StrictMode.VmPolicy.Builder}()
                  .detectLeakedSqlLiteObjects()
                  .detectLeakedClosableObjects()
                  .penaltyLog()
                  .penaltyDeath()
                  .build());


打开之后,当检测到有异常时,会抛出stack信息:


08-17 17:19:28.482 D/StrictMode(20180): StrictMode policy violation; ~duration=12 ms: android.os.StrictMode$StrictModeDiskWriteViolation: policy=29 violation=1
08-17 17:19:28.482 D/StrictMode(20180): at android.os.StrictMode$AndroidBlockGuardPolicy.onWriteToDisk(StrictMode.java:1108)
08-17 17:19:28.482 D/StrictMode(20180): at libcore.io.BlockGuardOs.fsync(BlockGuardOs.java:96)
08-17 17:19:28.482 D/StrictMode(20180): at java.io.FileDescriptor.sync(FileDescriptor.java:74)
08-17 17:19:28.482 D/StrictMode(20180): at android.os.FileUtils.sync(FileUtils.java:161)
08-17 17:19:28.482 D/StrictMode(20180): at android.app.SharedPreferencesImpl.writeToFile(SharedPreferencesImpl.java:597)
08-17 17:19:28.482 D/StrictMode(20180): at android.app.SharedPreferencesImpl.access$800(SharedPreferencesImpl.java:52)
08-17 17:19:28.482 D/StrictMode(20180): at android.app.SharedPreferencesImpl$2.run(SharedPreferencesImpl.java:511)
08-17 17:19:28.482 D/StrictMode(20180): at android.app.SharedPreferencesImpl.enqueueDiskWrite(SharedPreferencesImpl.java:532)
08-17 17:19:28.482 D/StrictMode(20180): at android.app.SharedPreferencesImpl.access$100(SharedPreferencesImpl.java:52)
08-17 17:19:28.482 D/StrictMode(20180): at android.app.SharedPreferencesImpl$EditorImpl.commit(SharedPreferencesImpl.java:454)
08-17 17:19:28.482 D/StrictMode(20180): at android.os.Handler.dispatchMessage(Handler.java:102)
08-17 17:19:28.482 D/StrictMode(20180): at android.os.Looper.loop(Looper.java:137)
08-17 17:19:28.482 D/StrictMode(20180): at android.app.ActivityThread.main(ActivityThread.java:4998)
08-17 17:19:28.482 D/StrictMode(20180): at java.lang.reflect.Method.invokeNative(Native Method)
08-17 17:19:28.482 D/StrictMode(20180): at java.lang.reflect.Method.invoke(Method.java:515)
08-17 17:19:28.482 D/StrictMode(20180): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)
08-17 17:19:28.482 D/StrictMode(20180): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)

08-17 17:19:28.482 D/StrictMode(20180): at dalvik.system.NativeStart.main(Native Method)


抛出的异常里面,可以看到操作的耗时情况,及可以从stack里面找到对应的位置和进行了什么操作,显然对于在主线程里面进行了IO等异常影响性能的进行检测,是非常有用的。

     栅栏里面,在application onCreate的时候,打开了StrictMode检测:

         strictmode.setthreadpolicy(new  strictmode.threadpolicy.builder()
                  .detectdiskreads()
                  .detectdiskwrites()
                  .detectnetwork()   // or .detectall() for all detectable problems
                  .penaltylog()
                  .build());


但是一直没有效果,在主线程里面进行了读写大文件,依然没有看到有StrictMode policy检测的log出来,调试了半天,也不知道什么原因,甚是奇怪。突然想,竟然在栅栏里面设置StrictMode没有用,那我主动在Activity onCreate的时候设置:

           public class ExampleActivity extends Activity{

                 ...

               public void onCreate(Bundle savedInstanceState){

          strictmode.setthreadpolicy(new  strictmode.threadpolicy.builder()
                  .detectdiskreads()
                  .detectdiskwrites()
                  .detectnetwork()   // or .detectall() for all detectable problems
                  .penaltylog()
                  .build());


这样开启以后,StrictMode竟然起了作用,难道栅栏的设置是没有效果的?越来越搞不懂了。

 查看framework StrictMode.java(在frameworks/base/core/java/android/os目录下),突然发现有StriceMode.java里面有得到thread policy的接口:

    /**

     * Returns the current thread's policy.

     */

    public static ThreadPolicy getThreadPolicy() {

        // TODO: this was a last minute Gingerbread API change (to

        // introduce VmPolicy cleanly) but this isn't particularly

        // optimal for users who might call this method often.  This

        // should be in a thread-local and not allocate on each call.

        return new ThreadPolicy(getThreadPolicyMask());

    }

那分别得到栅栏设置StrictMode、Activity onCreate里面设置了StrictMode、没有添加StrictMode检测三种情况的thread policy:

栅栏:

        thread policy : [StrictMode.ThreadPolicy; mask=516] , vm policy : [StrictMode.VmPolicy; mask=9744]

Activity onCreate:

         thread policy : [StrictMode.ThreadPolicy; mask=29] , vm policy : [StrictMode.VmPolicy; mask=9744]

无StrictMode检测:

        thread policy : [StrictMode.ThreadPolicy; mask=516] , vm policy : [StrictMode.VmPolicy; mask=0]


显然可以看到栅栏设置的StrictMode跟没有设置StrictMode检测的ThreadPolicy mask是一样的,而在Activity onCreate设置的StrictMode ThreadPolicy mask却是另一个值,通过在StrictMode.java check标志位的意义后发现,栅栏设置的StrictMode跟默认值一样,没有起到我们想要的效果,当然对比在Activity onCreate的值就能看出来,有两种可能存在:

1、栅栏里面StrictMode从始至终就没有把StrictMode打开。

2、栅栏设置成功了,存在其他地方设置StrictMode,从而使栅栏设置没有效果。


第1种情况好验证,在栅栏设置了StrictMode后,马上getThreadPolicy一下,结果得到如下log:

thread policy : [StrictMode.ThreadPolicy; mask=29] , vm policy : [StrictMode.VmPolicy; mask=9744]

说明栅栏设置成功了,那就是说第2种情况导致的栅栏StrictMode无效,那在重新设置了StrictMode呢?


查看StrictMode.java的代码可以发现:

   public static void setThreadPolicy(final ThreadPolicy policy) {
        setThreadPolicyMask(policy.mask);
    }

        setThreadPolicyMask(policy.mask);

    }

   

 private static voidsetThreadPolicyMask(final int policyMask) {

        // In addition to the Java-level thread-local in Dalvik's

        // BlockGuard, we also need to keep a native thread-local in

        // Binder in order to propagate the value across Binder calls,

           // even across native-only processes.  The two are kept in

         // sync via the callback to onStrictModePolicyChange, below.

        setBlockGuardPolicy(policyMask);

         // And set the Android native version...

        Binder.setThreadStrictModePolicy(policyMask);

    }

StriceMode的设置通过调用setThreadPolicy,然后再调用setThreadPolicyMask,在setThreadPolicyMask打印堆栈:


08-17 18:19:14.438 D/StrictDetecter(24163):at android.os.StrictMode.setThreadPolicy(Native Method)

08-17 18:19:14.438 D/StrictDetecter(24163):at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4334)

08-17 18:19:14.438 D/StrictDetecter(24163):at android.app.ActivityThread.access$1400(ActivityThread.java:135)

08-17 18:19:14.438 D/StrictDetecter(24163):at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1457)

08-17 18:19:14.438 D/StrictDetecter(24163):at android.os.Handler.dispatchMessage(Handler.java:102)

08-17 18:19:14.438 D/StrictDetecter(24163):at android.os.Looper.loop(Looper.java:137)

08-17 18:19:14.438 D/StrictDetecter(24163):at android.app.ActivityThread.main(ActivityThread.java:4998)

08-17 18:19:14.438 D/StrictDetecter(24163):at java.lang.reflect.Method.invokeNative(Native Method)

08-17 18:19:14.438 D/StrictDetecter(24163):at java.lang.reflect.Method.invoke(Method.java:515)

08-17 18:19:14.438 D/StrictDetecter(24163):at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)

08-17 18:19:14.438 D/StrictDetecter(24163):at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)

08-17 18:19:14.438 D/StrictDetecter(24163):at dalvik.system.NativeStart.main(Native Method)


在ActivityThread.java的handleBindApplication里面进行了StrictMode操作:

private void handleBindApplication(AppBindData data) {

...

 try {

                mInstrumentation.callApplicationOnCreate(app);

            } catch (Exception e) {

                if (!mInstrumentation.onException(app, e)) {

                    throw new RuntimeException(

                        "Unable to create application " + app.getClass().getName()

                        + ": " + e.toString(), e);

                }

            }

        } finally {

            StrictMode.setThreadPolicy(savedPolicy);

        }


最后把savedPolicy(函数前面保存的thread policy值)设置回去,似乎没有起到效果,Google的bug?不得而知。

终于知道原因了,栅栏在Application起来的时候设置StrictMode检测,framework在Activity 起来的时候会再设置一次,改变了原来的值,导致栅栏前面的设置没有效果,或者说栅栏设置StrictMode的时机不对,可以修改栅栏在Activity 起来的时候设置,避免这样的问题。

我不知道同事看了几天这个问题,但我知道我为此问题花费了不少于两天的时间,我本来是寄希望与同事的(技术高手),想放弃了,看了一两天后还是一点头绪都没有,到最后分析StrictMode.java时,看到有getThreadPolicy的接口时,打印policy的值,对比各种情况,才看到了一点曙光,最后一起联调,解决这个问题。不得不说,使用对比的方式去分析问题,有时真能得到意想不到的效果,无论是在性能分析,还是在其他地方(debug、生活、工作),因此记录一下,希望自己以后能更好的利用这种方法

0 0
原创粉丝点击