前一阵遇到手机在打开某些应用一直闪红框的问题,在此记录下分析问题的思路,可能有不准确的地方,请各位看官批评指正。
问题现象:有时候手机屏幕会不时的闪出红色矩形边框,不管是进入应用,在应用界面操作还是退出等操作,都有出现。(关闭严格模式没用,仍闪红框)
原因分析:原因在于手机启用了严格模式,正常情况只要关闭该模式再重启即可解决,不排除有极少个别情况是手机硬件或ROM的问题。所谓“严格模式”是指应用在主线程上执行长时间操作时闪烁屏幕,就是说打开某个应用后,退出后该应用仍在进程中运行,长时间后屏幕就会闪烁已提示用户在主线程上还有正在运行的应用程序。分析过程:通过查找源代码,发现在/frameworks/base/ services/java/com/android/server/wm/StrictModeFlash.java中的setVisibility()函数用来显示和关闭红框,而在base/services/java/com/android/server/wm/WindowManagerService.java中的mStrictModeFlash.setVisibility(on)调用这个函数。该函数位于如下函数中:
private void showStrictModeViolation(int arg, int pid) {
final boolean on = arg != 0;
synchronized(mWindowMap) {
。。。。。。。
SurfaceControl.openTransaction();
try {
// TODO(multi-display): support multiple displays
if (mStrictModeFlash == null) {
mStrictModeFlash = new StrictModeFlash(
getDefaultDisplayContentLocked().getDisplay(), mFxSession);
}
mStrictModeFlash.setVisibility(on);
} finally {
SurfaceControl.closeTransaction();
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
"<<< CLOSE TRANSACTION showStrictModeViolation");
}
}
}
调用showStrictModeViolation()的函数为,其中包括语句:
public void handleMessage(Message msg) {
。。。
case SHOW_STRICT_MODE_VIOLATION: {
showStrictModeViolation(msg.arg1, msg.arg2);
break;
}
。。。
<span style="white-space:pre"> </span>}
该函数为一个消息处理函数,接下来就要找哪块发送了这个包含SHOW_STRICT_MODE_VIOLATION消息。最后发现在这里:
public void showStrictModeViolation(boolean on) {
if (mHeadless) return;
int pid = Binder.getCallingPid();
mH.sendMessage(mH.obtainMessage(H.SHOW_STRICT_MODE_VIOLATION, on ? 1 : 0, pid));
}
然后继续往上找,调用这个函数的地方在yulong\frameworks\base\core\java\android\os\StrictMode.java.中,代码如下:
final IWindowManager windowManager = (info.policy & PENALTY_FLASH) != 0 ?
sWindowManager.get() : null;
if (windowManager != null) {
try {
windowManager.showStrictModeViolation(true);
} catch (RemoteException unused) {
}
}
当windowManager不为空的时候,会执行该语句,而windowManager由info.policy和PENALTY_FLASH决定,其中PENALTY_FLASH定义为等于0x800,是固定的。所以有影响的因素是info.policy,我们继续看它从哪里来。这部分代码都位于:
void handleViolationWithTimingAttempt(final ViolationInfo info) {}函数中,再往上找,调用该函数的代码如下:
void startHandlingViolationException(BlockGuard.BlockGuardPolicyException e) {
final ViolationInfo info = new ViolationInfo(e, e.getPolicy());
info.violationUptimeMillis = SystemClock.uptimeMillis();
handleViolationWithTimingAttempt(info);
}
可见这个info是由e决定的,而这个e的定义为BlockGuard.BlockGuardPolicyException。调用startHandlingViolationException这个函数的地方在哪里?继续往下走。
查找代码会发现有几个地方会调用该函数,其一如下:
// Part of BlockGuard.Policy interface:
public void onWriteToDisk() {
if ((mPolicyMask & DETECT_DISK_WRITE) == 0) {
return;
}
if (tooManyViolationsThisLoop()) {
return;
}
BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask);
e.fillInStackTrace();
startHandlingViolationException(e);
}
即在向磁盘写操作时,类似的包括磁盘读操作、网络访问。其中的BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask);是我们要的。mPolicyMask从哪里来?在如下这里定义:
private static class AndroidBlockGuardPolicy implements BlockGuard.Policy {
private int mPolicyMask;
。。。。
}
在该类的构造函数中,初始化如下:
public AndroidBlockGuardPolicy(final int policyMask) {
mPolicyMask = policyMask;
}
还有这个函数会改变mPolicyMask的值:
public void setPolicyMask(int policyMask) {
mPolicyMask = policyMask;
}
继续看哪里调用了setPolicyMask这个函数。原来在这:
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这个函数的地方在这
private static void onBinderStrictModePolicyChange(int newPolicy) {
setBlockGuardPolicy(newPolicy);
}
还有这块也调用了
private static void setThreadPolicyMask(final int policyMask) {
setBlockGuardPolicy(policyMask);
// And set the Android native version...
Binder.setThreadStrictModePolicy(policyMask);
}
在往上调用setThreadPolicyMask的函数如下,真正有用的地方在这里:
public static boolean conditionallyEnableDebugLogging() {
boolean doFlashes = SystemProperties.getBoolean(VISUAL_PROPERTY, false)
&& !amTheSystemServerProcess();
final boolean suppress = SystemProperties.getBoolean(DISABLE_PROPERTY, false);
// For debug builds, log event loop stalls to dropbox for analysis.
// Similar logic also appears in ActivityThread.java for system apps.
if (!doFlashes && (IS_USER_BUILD || suppress)) {
setCloseGuardEnabled(false);
return false;
}
<span style="background-color: rgb(255, 255, 51);"> // Eng builds have flashes on all the time. The suppression property
// overrides this, so we force the behavior only after the short-circuit
// check above.
/// M: Remove the force red frame
//if (IS_ENG_BUILD) {
// doFlashes = true;
//}
/// M: Remove the force red frame</span>
// Thread policy controls BlockGuard.
int threadPolicyMask = StrictMode.DETECT_DISK_WRITE |
StrictMode.DETECT_DISK_READ |
StrictMode.DETECT_NETWORK;
if (!IS_USER_BUILD) {
threadPolicyMask |= StrictMode.PENALTY_DROPBOX;
}
if (doFlashes) {
threadPolicyMask |= StrictMode.PENALTY_FLASH;
}
StrictMode.setThreadPolicyMask(threadPolicyMask);
// VM Policy controls CloseGuard, detection of Activity leaks,
// and instance counting.
if (IS_USER_BUILD) {
setCloseGuardEnabled(false);
} else {
VmPolicy.Builder policyBuilder = new VmPolicy.Builder().detectAll().penaltyDropBox();
policyBuilder.setClassInstanceLimit(Looper.class, 100); /// M: ALPS00312595
if (IS_ENG_BUILD) {
policyBuilder.penaltyLog();
}
setVmPolicy(policyBuilder.build());
setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
}
return true;
}
我们从设置中传进来的值也在这里体现,所以追踪到问题应该出现在这。由于源生的代码是没有问题的,所以对比后发现问题的原因是黄色的区域没有注释掉,导致Eng模式下会一直闪红框。