StrictMode严格模式原理分析

一、使用严格模式:

微信图片_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) {
            }
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容