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严格模式原理分析

    一、使用严格模式: 二、严格模式中是如何去检测,在哪个地方有注入StrictMode的代码:在源码中可以直接植入S...

  • StrictMode严格模式

    StrictMode是Android2.3加入的一个工具类,用于帮助开发者发现代码中的一些不规范的问题。比如网络操...

  • StrictMode 严格模式

    StrictMode 严格模式 开发者经常会无意地犯些错误:在主线程读写磁盘、访问网络,严格模式能够把帮助开发者监...

  • # 工具

    ## 严格模式 StrictMode(```React.StrictMode```),本质是一个组件,该组件不进行...

  • react Link跳转不生效

    可能是 React.StrictMode 严格模式的原因

  • StrictMode 严格模式应用

    Android 2.3提供一个称为严苛模式(StrictMode)的调试特性,Google称该特性已经使数百个An...

  • 性能基础:Android6.0 StrictMode 两个新特性

    StrictMode,严苛模式。在启动StrictMode的情况下,程序必须严格遵守某种“要求”干事,否则的话就会...

  • Android性能优化之StrictMode

    目录 StrictMode是什么 StrictMode从字面上翻译是严格模式的意思,它是Android提供的一种用...

  • React中StrictMode严格模式

    当我们使用npm create-react-app my-app创建一个react项目的时候,在项目根目录inde...

  • Android开发之StrictMode

    一. 简介 StrictMode(严格模式)是在Android 2.3(API 9)开始引入的类,StrictMo...

网友评论

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

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