StrictMode严格模式原理分析

作者: umbrella1 | 来源:发表于2018-05-25 22:42 被阅读31次

    一、使用严格模式:

    微信图片_20180525114217.png
    StrictMode严苛模式,是Android提供的一种运行时检测机制,一般用来检测在主线程做一些耗时动作,比如IO读写、数据库操作、Sp操作、Activity泄露、未关闭的Closable对象泄露等,以减少发生ANR等。严格模式主要有2个策略:一个是线程策略,即TreadPolicy是针对一个具体的线程,另一个是VM策略,即VmPolicy,是针对虚拟机的所有对象。
    当然可以添加Penalty(惩罚),一般我们都是用来打印日志、绘制红框等。

    二、严格模式中是如何去检测,在哪个地方有注入StrictMode的代码:
    在源码中可以直接植入StrictMode的检查代码、也可以植入代码是BlockGuard和CloseGuard的代码。
    我们先看下UML:

    2.png
    1、BlockGuard:
    public final class StrictMode {    
        public static void setThreadPolicy(final ThreadPolicy policy) {
            setThreadPolicyMask(policy.mask);
        }
        private static void setThreadPolicyMask(final int policyMask) {
            setBlockGuardPolicy(policyMask);
            Binder.setThreadStrictModePolicy(policyMask);
        }
    
        // Sets the policy in Dalvik/libcore (BlockGuard)
        private static void setBlockGuardPolicy(final int policyMask) {
            if (policyMask == 0) {
                BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY);
                return;
            }
            final BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
            final AndroidBlockGuardPolicy androidPolicy;
            if (policy instanceof AndroidBlockGuardPolicy) {
                androidPolicy = (AndroidBlockGuardPolicy) policy;
            } else {
                androidPolicy = threadAndroidPolicy.get();
                BlockGuard.setThreadPolicy(androidPolicy);
            }
            androidPolicy.setPolicyMask(policyMask);
        }
    }
    

    其中在setBlockGuardPolicy(policyMask)把相应的AndroidBlockGuardPolicy设置到BlockGuard类,
    并且Binder.setThreadStrictModePolicy()是Native层,当进程A发起跨进程调用进入到进程B后,进程B中的违规异常也是会通过Binder再传回进程A中。
    2、CloseGuard:

    public final class StrictMode {    
        public static void setVmPolicy(final VmPolicy policy) {
            synchronized (StrictMode.class) {
                sVmPolicy = policy;
                sVmPolicyMask = policy.mask;
                setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
                ...
            }
        }
        private static void setCloseGuardEnabled(boolean enabled) {
            if (!(CloseGuard.getReporter() instanceof AndroidCloseGuardReporter)) {
                CloseGuard.setReporter(new AndroidCloseGuardReporter());
            }
            CloseGuard.setEnabled(enabled);
        }
    }
    

    函数setCloseGuardEnabled注入AndroidCloseGuardReporter后,在Android很多代码都会使用CloseGuard.get()获取全局的CloseGuard进行检测输出打印日志出来。
    三、植入严格模式检测的代码:
    1)、FileInPutStream中:读写file时,有BlockGuard检测UI线程操作文件,有CloseGuard检测报告的未关闭文件等。

    class FileInputStream extends InputStream{
        private final CloseGuard guard = CloseGuard.get();
         public FileInputStream(File file) throws FileNotFoundException {
            ...
            BlockGuard.getThreadPolicy().onReadFromDisk();
            open(name);
            guard.open("close");
        }
        public void close() throws IOException {
            ...
            guard.close();
            ...
        }
        protected void finalize() throws IOException {
            if (guard != null) {
                guard.warnIfOpen();
            }
            if ((fd != null) &&  (fd != FileDescriptor.in)) {
                close();
            }
        }
    }
    

    2)、SQLiteCursor :在SQLiteCursor对象销毁时,会对Cursor是否关闭进行判断相应向StrictMode报告

    public class SQLiteCursor extends AbstractWindowedCursor {
         public SQLiteCursor(SQLiteCursorDriver driver, String editTable, SQLiteQuery query) {
            ...
            if (StrictMode.vmSqliteObjectLeaksEnabled()) {
                mStackTrace = new DatabaseObjectNotClosedException().fillInStackTrace();
            } else {
                mStackTrace = null;
            }
            ...
        }
        protected void finalize() {
            try {
                if (mWindow != null) {
                    if (mStackTrace != null) {
                        String sql = mQuery.getSql();
                        int len = sql.length();
                        StrictMode.onSqliteObjectLeaked(
                            "Finalizing a Cursor that has not been deactivated or closed. " +
                            "database = " + mQuery.getDatabase().getLabel() +
                            ", table = " + mEditTable +
                            ", query = " + sql.substring(0, (len > 1000) ? 1000 : len),
                            mStackTrace);
                    }
                    close();
                }
            } finally {
                super.finalize();
            }
        }
    }
    

    3)、Activity泄露,在ActivityThread中Activity的启动和销毁都有植入StrictMode相应的代码去检测Activity的引用计数,来判断是否有泄露,在StrictMode.decrementExpectedActivityCount(activityClass);会手动System.gc();

    public final class ActivityThread {
        private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
            ...
            Activity activity = null;
            try {
                java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
                activity = mInstrumentation.newActivity(
                        cl, component.getClassName(), r.intent);
                StrictMode.incrementExpectedActivityCount(activity.getClass());
                ...
            } catch (Exception e) {
            }
           ...
           return activity;
        }
        private ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
                int configChanges, boolean getNonConfigInstance) {
                ...
                try {
                    r.activity.mCalled = false;
                    mInstrumentation.callActivityOnDestroy(r.activity);
                    ...
                } catch (Exception e) {      
                    }
                }
            StrictMode.decrementExpectedActivityCount(activityClass);
            return r;
        }
    }
    

    4)、SharedPreferencesImpl 中getString、getInt等也植入了BlockGuard

    final class SharedPreferencesImpl implements SharedPreferences {
        @Nullable
        public String getString(String key, @Nullable String defValue) {
            synchronized (this) {
                awaitLoadedLocked();
                ...
            }
        }
    
        @Nullable
        public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
            synchronized (this) {
                awaitLoadedLocked();
                ...
            }
        }
    
        public int getInt(String key, int defValue) {
            synchronized (this) {
                awaitLoadedLocked();
                ...
            }
        }
        private void awaitLoadedLocked() {
            if (!mLoaded) {
                // Raise an explicit StrictMode onReadFromDisk for this
                // thread, since the real read will be in a different
                // thread and otherwise ignored by StrictMode.
                BlockGuard.getThreadPolicy().onReadFromDisk();
            }
            while (!mLoaded) {
                try {
                    wait();
                } catch (InterruptedException unused) {
                }
            }
        }
    }
    

    相关文章

      网友评论

        本文标题:StrictMode严格模式原理分析

        本文链接:https://www.haomeiwen.com/subject/bwkujftx.html