Android 系统中, ActivityManagerService( 简称 AMS)和WindowManagerService( 简 称 WMS)会检测App的响应时间,如果App在特定时间无法相应屏幕触摸或键盘输入时间,或者特定事件没有处理完毕,就会出现 ANR。
InputDispatching Timeout:5 秒内无法响应屏幕触摸事件或键盘输入事件BroadcastQueue Timeout :在执行前台广播(BroadcastReceiver)的 onReceive()函数时 10 秒没有处理完成,后台为 60 秒。Service Timeout :前台服务 20 秒内,后台服务在 200 秒内没有执行完毕。ContentProvider Timeout :ContentProvider 的 publish 在 10s 内没进行完。Service Timeout 是位于 ActivityManager 线程中的 AMS.MainHandler 收到 SERVICE_TIMEOUT_MSG 消息时触发。
Service 进程 attach 到 system_server 进程的过程中会调用realStartServiceLocked ,紧接着mAm.mHandler.sendMessageAtTime() 来发送一个延时消息,延时的时常是定义好的,如前台 Service 的 20 秒。ActivityManager 线程中的 AMS.MainHandler 收到 SERVICE_TIMEOUT_MSG 消息时会触发。
调用 ActiveServices.realStartServiceLocked 方法
IApplicationThread thread; //ActivityThread 的内部类
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException {
...
//发送 delay 消息(SERVICE_TIMEOUT_MSG
bumpServiceExecutingLocked(r, execInFg, "create");
try {
if (LOG_SERVICE_START_STOP) {
...
//最终执行服务的 onCreate()方法
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
app.getReportedProcState());
r.postNotification();
created = true;
} catch (DeadObjectException e) {
Slog.w(TAG, "Application dead when creating service " + r);
mAm.appDiedLocked(app, "Died when creating service");
throw e;
} finally {
..
}
...
}
ActiveServices.java
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
...
long now = SystemClock.uptimeMillis();
if (r.executeNesting == 0) {
r.executeFg = fg;
ServiceState stracker = r.getTracker();
if (stracker != null) {
stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
}
if (r.app != null) {
r.app.executingServices.add(r);
r.app.execServicesFg |= fg;
if (timeoutNeeded && r.app.executingServices.size() == 1) {
scheduleServiceTimeoutLocked(r.app);
}
}
} else if (r.app != null && fg && !r.app.execServicesFg) {
r.app.execServicesFg = true;
if (timeoutNeeded) {
scheduleServiceTimeoutLocked(r.app);
}
}
r.executeFg |= fg;
r.executeNesting++;
r.executingStart = now;
}
static final int SERVICE_TIMEOUT = 20*1000; //前台服务 20 秒内
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10; //后台服务在 200 秒
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
}
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
//发送延时消息
//当超时后仍没有 remove 该SERVICE_TIMEOUT_MSG 消息,则执行 service Timeout 流程
mAm.mHandler.sendMessageDelayed(msg,
proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}
进入 ActivityManagerService#MainHandler处理消息
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
final MainHandler mHandler;
final ActiveServices mServices;
final class MainHandler extends Handler {
public MainHandler(Looper looper) {
super(looper, null, true);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case GC_BACKGROUND_PROCESSES_MSG: {
synchronized (ActivityManagerService.this) {
performAppGcsIfAppropriateLocked();
}
} break;
case SERVICE_TIMEOUT_MSG: { //处理 service 的超时时间 ANR
mServices.serviceTimeout((ProcessRecord)msg.obj);
} break;
...
}
}
}
进入ActiveServices#serviceTimeout 进行处理
void serviceTimeout(ProcessRecord proc) {
String anrMessage = null;
synchronized(mAm) {
if (proc.isDebugging()) {
// The app's being debugged, ignore timeout.
return;
}
if (proc.executingServices.size() == 0 || proc.thread == null) {
return;
}
final long now = SystemClock.uptimeMillis();
final long maxTime = now -
(proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
ServiceRecord timeout = null;
long nextTime = 0;
for (int i=proc.executingServices.size()-1; i>=0; i--) {
ServiceRecord sr = proc.executingServices.valueAt(i);
if (sr.executingStart < maxTime) {
timeout = sr;
break;
}
if (sr.executingStart > nextTime) {
nextTime = sr.executingStart;
}
}
if (timeout != null && mAm.mProcessList.mLruProcesses.contains(proc)) {
Slog.w(TAG, "Timeout executing service: " + timeout);
StringWriter sw = new StringWriter();
PrintWriter pw = new FastPrintWriter(sw, false, 1024);
pw.println(timeout);
timeout.dump(pw, " ");
pw.close();
mLastAnrDump = sw.toString();
mAm.mHandler.removeCallbacks(mLastAnrDumpClearer);
mAm.mHandler.postDelayed(mLastAnrDumpClearer, LAST_ANR_LIFETIME_DURATION_MSECS);
//异常 消息
anrMessage = "executing service " + timeout.shortInstanceName;
} else {
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg
? (nextTime+SERVICE_TIMEOUT) : (nextTime + SERVICE_BACKGROUND_TIMEOUT));
}
}
if (anrMessage != null) {
//处理 NAR
mAm.mAnrHelper.appNotResponding(proc, anrMessage);
}
}
无论是四大组件或者进程等只要发生ANR,最终都会调用 AMS.appNotResponding() 方法。
class AnrHelper {
//保存 ANR 信息
private final ArrayList<AnrRecord> mAnrRecords = new ArrayList<>();
private final AtomicBoolean mRunning = new AtomicBoolean(false);
void appNotResponding(ProcessRecord anrProcess, String annotation) {
appNotResponding(anrProcess, null /* activityShortComponentName */, null /* aInfo */,
null /* parentShortComponentName */, null /* parentProcess */,
false /* aboveSystem */, annotation);
}
void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName,
WindowProcessController parentProcess, boolean aboveSystem, String annotation) {
synchronized (mAnrRecords) {
mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo,
parentShortComponentName, parentProcess, aboveSystem, annotation));
}
startAnrConsumerIfNeeded();
}
private void startAnrConsumerIfNeeded() {
if (mRunning.compareAndSet(false, true)) {
new AnrConsumerThread().start();
}
}
//执行 ANR 的线程
private class AnrConsumerThread extends Thread {
AnrConsumerThread() {
super("AnrConsumer");
}
private AnrRecord next() {
synchronized (mAnrRecords) {
return mAnrRecords.isEmpty() ? null : mAnrRecords.remove(0);
}
}
@Override
public void run() {
AnrRecord r;
while ((r = next()) != null) {
final long startTime = SystemClock.uptimeMillis();
// If there are many ANR at the same time, the latency may be larger. If the latency
// is too large, the stack trace might not be meaningful.
final long reportLatency = startTime - r.mTimestamp;
final boolean onlyDumpSelf = reportLatency > EXPIRED_REPORT_TIME_MS;
r.appNotResponding(onlyDumpSelf);
final long endTime = SystemClock.uptimeMillis();
Slog.d(TAG, "Completed ANR of " + r.mApp.processName + " in "
+ (endTime - startTime) + "ms, latency " + reportLatency
+ (onlyDumpSelf ? "ms (expired, only dump ANR app)" : "ms"));
}
mRunning.set(false);
synchronized (mAnrRecords) {
// The race should be unlikely to happen. Just to make sure we don't miss.
if (!mAnrRecords.isEmpty()) {
startAnrConsumerIfNeeded();
}
}
}
}
//存储 ANR 信息类
private static class AnrRecord {
final ProcessRecord mApp;
final String mActivityShortComponentName;
final String mParentShortComponentName;
final String mAnnotation;
final ApplicationInfo mAppInfo;
final WindowProcessController mParentProcess;
final boolean mAboveSystem;
final long mTimestamp = SystemClock.uptimeMillis();
AnrRecord(ProcessRecord anrProcess, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName,
WindowProcessController parentProcess, boolean aboveSystem, String annotation) {
mApp = anrProcess;
mActivityShortComponentName = activityShortComponentName;
mParentShortComponentName = parentShortComponentName;
mAnnotation = annotation;
mAppInfo = aInfo;
mParentProcess = parentProcess;
mAboveSystem = aboveSystem;
}
void appNotResponding(boolean onlyDumpSelf) {
mApp.appNotResponding(mActivityShortComponentName, mAppInfo,
mParentShortComponentName, mParentProcess, mAboveSystem, mAnnotation,
onlyDumpSelf);
}
}
}
进入 ActivityThread#ApplicationThread#scheduleCreateService 的方法。
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false);
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
//发送 CREATE_SERVICE 消息
sendMessage(H.CREATE_SERVICE, s);
}
调用 ActivityThread#H 类发送消息
class H extends Handler {
public void handleMessage(Message msg)
switch (msg.what) {
case CREATE_SERVICE:
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
("serviceCreate: " + String.valueOf(msg.obj)));
}
handleCreateService((CreateServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
}
private void handleCreateService(CreateServiceData data) {
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null;
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
//创建 ContextImpl 对象
ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
//创建 Application 对象
Application app = packageInfo.makeApplication(false, mInstrumentation);
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
// Service resources must be initialized with the same loaders as the application
// context.
context.getResources().addLoaders(
app.getResources().getLoaders().toArray(new ResourcesLoader[0]));
context.setOuterContext(service);
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
//调用服务 onCreate()方法
service.onCreate();
mServices.put(data.token, service);
try {
//取消 AMS.MainHandler 的延时消息
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
这个方法中会创建目标服务对象,以及回调常用的 Service 的 onCreate() 方法,紧接着通过 serviceDoneExecuting() 回到 system_server 执行取消 AMS.MainHandler 的延时消息
进入ActivityManagerService#serviceDoneExecuting 方法
final ActiveServices mServices;
public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
synchronized(this) {
if (!(token instanceof ServiceRecord)) {
Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token);
throw new IllegalArgumentException("Invalid service token");
}
mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
}
}
调用 ActiveServices#serviceDoneExecutingLocked 方法
void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
boolean inDestroying = mDestroyingServices.contains(r);
if (r != null) {
if (type == ActivityThread.SERVICE_DONE_EXECUTING_START) {
r.callStart = true;
switch (res) {
case Service.START_STICKY_COMPATIBILITY:
case Service.START_STICKY: {
// We are done with the associated start arguments.
r.findDeliveredStart(startId, false, true);
// Don't stop if killed.
r.stopIfKilled = false;
break;
}
case Service.START_NOT_STICKY: {
// We are done with the associated start arguments.
r.findDeliveredStart(startId, false, true);
if (r.getLastStartId() == startId) {
r.stopIfKilled = true;
}
break;
}
case Service.START_REDELIVER_INTENT: {
ServiceRecord.StartItem si = r.findDeliveredStart(startId, false, false);
if (si != null) {
si.deliveryCount = 0;
si.doneExecutingCount++;
// Don't stop if killed.
r.stopIfKilled = true;
}
break;
}
case Service.START_TASK_REMOVED_COMPLETE: {
r.findDeliveredStart(startId, true, true);
break;
}
default:
throw new IllegalArgumentException(
"Unknown service start result: " + res);
}
if (res == Service.START_STICKY_COMPATIBILITY) {
r.callStart = false;
}
} else if (type == ActivityThread.SERVICE_DONE_EXECUTING_STOP) {
if (!inDestroying) {
if (r.app != null) {
Slog.w(TAG, "Service done with onDestroy, but not inDestroying: "
+ r + ", app=" + r.app);
}
} else if (r.executeNesting != 1) {
Slog.w(TAG, "Service done with onDestroy, but executeNesting="
+ r.executeNesting + ": " + r);
// Fake it to keep from ANR due to orphaned entry.
r.executeNesting = 1;
}
}
final long origId = Binder.clearCallingIdentity();
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
Binder.restoreCallingIdentity(origId);
} else {
Slog.w(TAG, "Done executing unknown service from pid "
+ Binder.getCallingPid());
}
}
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "<<< DONE EXECUTING " + r
+ ": nesting=" + r.executeNesting
+ ", inDestroying=" + inDestroying + ", app=" + r.app);
else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
"<<< DONE EXECUTING " + r.shortInstanceName);
r.executeNesting--;
if (r.executeNesting <= 0) {
if (r.app != null) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"Nesting at 0 of " + r.shortInstanceName);
r.app.execServicesFg = false;
r.app.executingServices.remove(r);
if (r.app.executingServices.size() == 0) {
if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
"No more executingServices of " + r.shortInstanceName);
//移除当前服务所在进程中没有正在执行的 service
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
} else if (r.executeFg) {
// Need to re-evaluate whether the app still needs to be in the foreground.
for (int i=r.app.executingServices.size()-1; i>=0; i--) {
if (r.app.executingServices.valueAt(i).executeFg) {
r.app.execServicesFg = true;
break;
}
}
}
if (inDestroying) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"doneExecuting remove destroying " + r);
mDestroyingServices.remove(r);
r.bindings.clear();
}
mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
}
r.executeFg = false;
if (r.tracker != null) {
final int memFactor = mAm.mProcessStats.getMemFactorLocked();
final long now = SystemClock.uptimeMillis();
r.tracker.setExecuting(false, memFactor, now);
r.tracker.setForeground(false, memFactor, now);
if (finishing) {
r.tracker.clearCurrentOwner(r, false);
r.tracker = null;
}
}
if (finishing) {
if (r.app != null && !r.app.isPersistent()) {
r.app.stopService(r);
r.app.updateBoundClientUids();
if (r.whitelistManager) {
updateWhitelistManagerLocked(r.app);
}
}
r.setProcess(null);
}
}
}
此方法中 Service 逻辑处理完成则移除之前延时的消息SERVICE_TIMEOUT_MSG 。如果没有执行完毕不调用这个方法,则超时后会发出 SERVICE_TIMEOUT_MSG 来告知ANR 发生。
我正在尝试在配备ARMv7处理器的SynologyDS215j上安装ruby2.2.4或2.3.0。我用了optware-ng安装gcc、make、openssl、openssl-dev和zlib。我根据README中的说明安装了rbenv(版本1.0.0-19-g29b4da7)和ruby-build插件。.这些是随optware-ng安装的软件包及其版本binutils-2.25.1-1gcc-5.3.0-6gconv-modules-2.21-3glibc-opt-2.21-4libc-dev-2.21-1libgmp-6.0.0a-1libmpc-1.0.2-1libm
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visitthehelpcenter.关闭9年前。我需要从基于ruby的应用程序使用AmazonSimpleNotificationService,但不知道从哪里开始。您对从哪里开始有什么建议吗?
下面的代码工作正常:person={:a=>:A,:b=>:B,:c=>:C}berson={:a=>:A1,:b=>:B1,:c=>:C1}kerson=person.merge(berson)do|key,oldv,newv|ifkey==:aoldvelsifkey==:bnewvelsekeyendendputskerson.inspect但是如果我在“ifblock”中添加return,我会得到一个错误:person={:a=>:A,:b=>:B,:c=>:C}berson={:a=>:A1,:b=>:B1,:c=>:C1}kerson=person.merge(berson
我正在使用macos,我想使用ruby驱动程序连接到sqlserver。我想使用tiny_tds,但它给出了缺少free_tds的错误,但它已经安装了。怎么能过这个?~brewinstallfreetdsWarning:freetds-0.91.112alreadyinstalled~sudogeminstalltiny_tdsBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtiny_tds:ERROR:Failedtobuildgemnativeextension.完整日志如下:/System
我有以下haml:9%strongAskedby:10=link_to@user.full_name,user_path(@user)11.small="(#{@question.created_at.strftime("%B%d,%Y")})"这当前将链接和日期放在不同的行上,当它看起来像“链接(日期)”并且日期的类跨度为小...... 最佳答案 您的代码将生成类似这样的html:Askedby:UsernameApril26,2011当您使用类似.small的东西(即使用点而不指定元素类型)时,haml会创建一个implicit
下面有没有更优雅的方法来实现这个:输入:array=[1,1,1,0,0,1,1,1,1,0]输出:4我的算法:streak=0max_streak=0arr.eachdo|n|ifn==1streak+=1elsemax_streak=streakifstreak>max_streakstreak=0endendputsmax_streak 最佳答案 类似于w0lf'sanswer,但通过从chunk返回nil来跳过元素:array.chunk{|x|x==1||nil}.map{|_,x|x.size}.max
有没有一种有效的方法来做到这一点。我有一个数组a=[1,2,2,3,1,2]我想按升序输出出现的频率。示例[[3,1],[1,2],[2,3]]这是我的ruby代码。b=a.group_by{|x|x}out={}b.eachdo|k,v|out[k]=v.sizeendout.sort_by{|k,v|v} 最佳答案 a=[1,2,2,3,1,2]a.each_with_object(Hash.new(0)){|m,h|h[m]+=1}.sort_by{|k,v|v}#=>[[3,1],[1,2],[2,3]]
在MacOS更新之前,它一直运行良好。我重新安装了RVM、rails、ruby等等。到目前为止没有任何效果。在我的Mac终端中,我可以生成一个é,但是在控制台中,我可以生成字符,使用alt+character,然后当我键入字符分配给的字母,它会删除该字符。在我的~/.rvmrc中:exportruby_configure_flags="--with-readline-dir=/usr/local/Cellar/readline/6.2.4"有什么想法吗?到目前为止,我已经明确地让它工作了,包括readline-rb。我猜我的全局要求不工作。gem'rb-readline','~>0.4
我认为我对线程在ruby中的工作原理存在根本性的误解,我希望获得一些见解。我想要一个简单的生产者和消费者。首先,生产者线程从文件中提取行并将它们粘贴到SizedQueue中;当那些用完时,在末端贴上一些token,让消费者知道事情已经完成。require'thread'numthreads=2filename='edition-2009-09-11.txt'bq=SizedQueue.new(4)producerthread=Thread.new(bq)do|queue|File.open(filename)do|f|f.eachdo|r|queue现在有几个消费者。为简单起见,让
我最近开始了一个项目,团队决定我们希望使用jQuery而不是Prototype/Scriptaculous来满足我们的javascript需求。我们设置了我们的项目,并开始切换。插件已安装viatheseinstructions,一切都按计划进行。不久之后,当尝试运行“./script/server”时,我们收到以下错误:=>Rails2.3.2applicationstartingonhttp://0.0.0.0:3000/usr/local/lib/ruby/gems/1.9.1/gems/activesupport-2.3.2/lib/active_support/depende