ANR日志输出

appNotResponding

//com.android.server.am.AppErrors.java/* app: 当前发生ANR的进程* activity: 发生ANR的界面* parent: 发生ANR的界面的上一级界面* aboveSystem: * annotation: 发生ANR的原因*/
final void appNotResponding(ProcessRecord app, ActivityRecord activity,ActivityRecord parent, boolean aboveSystem, final String annotation) {// 构建firstPids和lastPids数组// firstPids: 用于保存ANR进程及其父进程,system_server进程和persistent的进程// lastPids: 用于保存除firstPids外的其他进程ArrayList<Integer> firstPids = new ArrayList<Integer>(5);SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20);if (mService.mController != null) {try {// 0 == continue, -1 = kill process immediatelyint res = mService.mController.appEarlyNotResponding(app.processName, app.pid, annotation);if (res < 0 && app.pid != MY_PID) {app.kill("anr", true);}} catch (RemoteException e) {mService.mController = null;Watchdog.getInstance().setActivityController(null);}}long anrTime = SystemClock.uptimeMillis();if (ActivityManagerService.MONITOR_CPU_USAGE) {// 更新CPU使用信息mService.updateCpuStatsNow();}// Unless configured otherwise, swallow ANRs in background processes & kill the process.// 如果配置了ANR_SHOW_BACKGROUND(anr_show_background)值为非空,则会弹出一个对话框,否则静默killboolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;boolean isSilentANR;// 跳过下面这些场景下的ANRsynchronized (mService) {// PowerManager.reboot() can block for a long time, so ignore ANRs while shutting down.//正在关机的if (mService.mShuttingDown) {Slog.i(TAG, "During shutdown skipping ANR: " + app + " " + annotation);return;//已经有一个ANR弹出框时} else if (app.notResponding) {Slog.i(TAG, "Skipping duplicate ANR: " + app + " " + annotation);return;//正在处理crash的} else if (app.crashing) {Slog.i(TAG, "Crashing app skipping ANR: " + app + " " + annotation);return;//被AMS kill的} else if (app.killedByAm) {Slog.i(TAG, "App already killed by AM skipping ANR: " + app + " " + annotation);return;// 进程已经被kill} else if (app.killed) {Slog.i(TAG, "Skipping died app ANR: " + app + " " + annotation);return;}// In case we come through here for the same app before completing// this one, mark as anring now so we will bail out.//防止同一个进程重复dump信息app.notResponding = true;//1.Log the ANR to the event log. 事件记录到eventlog中EventLog.writeEvent(EventLogTags.AM_ANR, app.userId, app.pid,app.processName, app.info.flags, annotation);// Dump thread traces as quickly as we can, starting with "interesting" processes.// 将当前进程添加到firstPidsfirstPids.add(app.pid);// 2.Don't dump other PIDs if it's a background ANR//showBackground为false(不显示后台ANR的dialog)isSilentANR = !showBackground && !isInterestingForBackgroundTraces(app);if (!isSilentANR) {int parentPid = app.pid;if (parent != null && parent.app != null && parent.app.pid > 0) {parentPid = parent.app.pid;}if (parentPid != app.pid) firstPids.add(parentPid);// MY_PID为system_server的PID,将system_server进程添加到firstPidsif (MY_PID != app.pid && MY_PID != parentPid) firstPids.add(MY_PID);for (int i = mService.mLruProcesses.size() - 1; i >= 0; i--) {ProcessRecord r = mService.mLruProcesses.get(i);if (r != null && r.thread != null) {int pid = r.pid;if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {// 将persistent进程添加到firstPidsif (r.persistent) {firstPids.add(pid);if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);} else if (r.treatLikeActivity) {firstPids.add(pid);if (DEBUG_ANR) Slog.i(TAG, "Adding likely IME: " + r);} else {//其他进程添加到lastPidslastPids.put(pid, Boolean.TRUE);if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r);}}}}}}// Log the ANR to the main log.// 把ANR信息输出到main logStringBuilder info = new StringBuilder();info.setLength(0);info.append("ANR in ").append(app.processName);if (activity != null && activity.shortComponentName != null) {info.append(" (").append(activity.shortComponentName).append(")");}info.append("\n");info.append("PID: ").append(app.pid).append("\n");if (annotation != null) {info.append("Reason: ").append(annotation).append("\n");}if (parent != null && parent != activity) {info.append("Parent: ").append(parent.shortComponentName).append("\n");}ProcessCpuTracker processCpuTracker = new ProcessCpuTracker(true);// don't dump native PIDs for background ANRs unless it is the process of interestString[] nativeProcs = null;if (isSilentANR) {for (int i = 0; i < NATIVE_STACKS_OF_INTEREST.length; i++) {if (NATIVE_STACKS_OF_INTEREST[i].equals(app.processName)) {nativeProcs = new String[] { app.processName };break;}}} else {nativeProcs = NATIVE_STACKS_OF_INTEREST;}// pids为NATIVE_STACKS_OF_INTEREST中定义的几个进程int[] pids = nativeProcs == null ? null : Process.getPidsForCommands(nativeProcs);ArrayList<Integer> nativePids = null;if (pids != null) {nativePids = new ArrayList<Integer>(pids.length);for (int i : pids) {nativePids.add(i);}}// For background ANRs, don't pass the ProcessCpuTracker to// avoid spending 1/2 second collecting stats to rank lastPids.
// 输出traces信息,后面细说File tracesFile = ActivityManagerService.dumpStackTraces(true, firstPids,(isSilentANR) ? null : processCpuTracker,(isSilentANR) ? null : lastPids,nativePids);String cpuInfo = null;
// cpu信息统计,各个进程的cpu使用情况if (ActivityManagerService.MONITOR_CPU_USAGE) {mService.updateCpuStatsNow();synchronized (mService.mProcessCpuTracker) {// 记录ANR之前的cpu使用情况(CPU usage from 38980ms to 0ms ago)cpuInfo = mService.mProcessCpuTracker.printCurrentState(anrTime);}info.append(processCpuTracker.printCurrentLoad());info.append(cpuInfo);}// 记录从anr时间开始的cpu使用情况(CPU usage from 72ms to 465ms later)info.append(processCpuTracker.printCurrentState(anrTime));// 输出info信息,包含ANR的Reason、CPU负载信息以及使用率Slog.e(TAG, info.toString());if (tracesFile == null) {// There is no trace file, so dump (only) the alleged culprit's threads to the log
// 如果trace为空,则发送singal 3到发送ANR的进程,相当于adb shell kill -3 pidProcess.sendSignal(app.pid, Process.SIGNAL_QUIT);}// 将traces文件和CPU使用率信息保存到dropbox,即data/system/dropboxStatsLog.write(StatsLog.ANR_OCCURRED, app.uid, app.processName,activity == null ? "unknown": activity.shortComponentName, annotation,(app.info != null) ? (app.info.isInstantApp()? StatsLog.ANROCCURRED__IS_INSTANT_APP__TRUE: StatsLog.ANROCCURRED__IS_INSTANT_APP__FALSE): StatsLog.ANROCCURRED__IS_INSTANT_APP__UNAVAILABLE,app != null ? (app.isInterestingToUserLocked()? StatsLog.ANROCCURRED__FOREGROUND_STATE__FOREGROUND: StatsLog.ANROCCURRED__FOREGROUND_STATE__BACKGROUND): StatsLog.ANROCCURRED__FOREGROUND_STATE__UNKNOWN);mService.addErrorToDropBox("anr", app, app.processName, activity, parent, annotation,cpuInfo, tracesFile, null);if (mService.mController != null) {try {// 0 == show dialog, 1 = keep waiting, -1 = kill process immediatelyint res = mService.mController.appNotResponding(app.processName, app.pid, info.toString());if (res != 0) {if (res < 0 && app.pid != MY_PID) {app.kill("anr", true);} else {synchronized (mService) {mService.mServices.scheduleServiceTimeoutLocked(app);}}return;}} catch (RemoteException e) {mService.mController = null;Watchdog.getInstance().setActivityController(null);}}synchronized (mService) {mService.mBatteryStatsService.noteProcessAnr(app.processName, app.uid);
// 后台进程ANR,则直接killif (isSilentANR) {app.kill("bg anr", true);return;}// Set the app's notResponding state, and look up the errorReportReceivermakeAppNotRespondingLocked(app,activity != null ? activity.shortComponentName : null,annotation != null ? "ANR " + annotation : "ANR",info.toString());// Bring up the infamous App Not Responding dialogMessage msg = Message.obtain();msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;msg.obj = new AppNotRespondingDialog.Data(app, activity, aboveSystem);mService.mUiHandler.sendMessage(msg);}
}
  1. 输出ANR Reason信息到Events log中,关键字是am_anr,一般都是用这个信息来确定Anr的发生时间
  2. 如果是后台的anr,即isSilentANR值为true,那么不显示ANR对话框,直接kill掉ANR所在进程
  3. 输出ANR 信息到main log中,关键字是ANR in,含有Cpu负载信息,一般都是用这个看ANR发生时候的其他进程的资源占用情况
  4. 调用dumpStackTraces去生成trace文件,这个trace文件有哪些进程呢?
    • firstPids队列:第一个是ANR进程,第二个是system_server,剩余是所有persistent进程
    • Native队列:是指/system/bin/目录的mediaserver,sdcard 以及surfaceflinger进程; NATIVE_STACKS_OF_INTEREST
    • lastPids队列: 是指mLruProcesses中的不属于firstPids的所有进程。
  5. 将traces文件和 CPU使用情况信息保存到dropbox,即data/system/dropbox目录
  6. 弹窗告知用户
  7. am_anr关键字比ANR in要先打印,所以更接近ANR的实际发生时间

dumpStackTraces

//com.android.server.am.ActivityManagerService.java
public static File dumpStackTraces(boolean clearTraces, ArrayList<Integer> firstPids,ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids,ArrayList<Integer> nativePids) {ArrayList<Integer> extraPids = null;// Measure CPU usage as soon as we're called in order to get a realistic sampling// of the top users at the time of the request.// 一旦调用此方法就马上计算CPU使用率以在请求的时候获取top用户的实际采样if (processCpuTracker != null) {processCpuTracker.init();try {Thread.sleep(200);} catch (InterruptedException ignored) {}// 测量CPU使用情况processCpuTracker.update();// We'll take the stack crawls of just the top apps using CPU.final int N = processCpuTracker.countWorkingStats();extraPids = new ArrayList<>();// 从lastPids中选取CPU使用率top 5的进程,晚些时机输出这些进程的stacksfor (int i = 0; i < N && extraPids.size() < 5; i++) {ProcessCpuTracker.Stats stats = processCpuTracker.getWorkingStats(i);if (lastPids.indexOfKey(stats.pid) >= 0) {if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid " + stats.pid);extraPids.add(stats.pid);} else if (DEBUG_ANR) {Slog.d(TAG, "Skipping next CPU consuming process, not a java proc: "+ stats.pid);}}}boolean useTombstonedForJavaTraces = false;File tracesFile;//如果dalvik.vm.stack-trace-dir没有配置,trace就写到全局文件data/anr/traces.txt中final String tracesDirProp = SystemProperties.get("dalvik.vm.stack-trace-dir", "");if (tracesDirProp.isEmpty()) {// When dalvik.vm.stack-trace-dir is not set, we are using the "old" trace// dumping scheme. All traces are written to a global trace file (usually// "/data/anr/traces.txt") so the code below must take care to unlink and recreate// the file if requested.//// This mode of operation will be removed in the near future.String globalTracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);if (globalTracesPath.isEmpty()) {Slog.w(TAG, "dumpStackTraces: no trace path configured");return null;}tracesFile = new File(globalTracesPath);try {//删除旧的,创建新的if (clearTraces && tracesFile.exists()) {tracesFile.delete();}tracesFile.createNewFile();//注意这里的权限设置 8.0以前的版本是没有的FileUtils.setPermissions(globalTracesPath, 0666, -1, -1); // -rw-rw-rw-} catch (IOException e) {Slog.w(TAG, "Unable to prepare ANR traces file: " + tracesFile, e);return null;}} else {File tracesDir = new File(tracesDirProp);// When dalvik.vm.stack-trace-dir is set, we use the "new" trace dumping scheme.// Each set of ANR traces is written to a separate file and dumpstate will process// all such files and add them to a captured bug report if they're recent enough.maybePruneOldTraces(tracesDir);// NOTE: We should consider creating the file in native code atomically once we've// gotten rid of the old scheme of dumping and lot of the code that deals with paths// can be removed.//以当前时间命名的trace文件 yyyy-MM-dd-HH-mm-ss-SSStracesFile = createAnrDumpFile(tracesDir);if (tracesFile == null) {return null;}useTombstonedForJavaTraces = true;}dumpStackTraces(tracesFile.getAbsolutePath(), firstPids, nativePids, extraPids,useTombstonedForJavaTraces);return tracesFile;
}

总结一下上面代码,这段代码并没有真正的执行dump操作,只是确定了trace文件路径,如果”dalvik.vm.stack-trace-dir”这个属性没有配置,就使用旧的dump策略,trace信息写入到全局trace文件/data/anr/traces.txt中,删除旧的traces文件,创建新的traces文件;如果”dalvik.vm.stack-trace-dir”属性被配置了,就创建格式为anr_yyyy-MM-dd-HH-mm-ss-SSS的文件。

private static void dumpStackTraces(String tracesFile, ArrayList<Integer> firstPids,ArrayList<Integer> nativePids, ArrayList<Integer> extraPids,boolean useTombstonedForJavaTraces) {// We don't need any sort of inotify based monitoring when we're dumping traces via// tombstoned. Data is piped to an "intercept" FD installed in tombstoned so we're in full// control of all writes to the file in question.final DumpStackFileObserver observer;if (useTombstonedForJavaTraces) {observer = null;} else {// Use a FileObserver to detect when traces finish writing.// The order of traces is considered important to maintain for legibility.observer = new DumpStackFileObserver(tracesFile);}// We must complete all stack dumps within 20 seconds.// 所有的dump操作需要在20秒之内完成long remainingTime = 20 * 1000;try {if (observer != null) {observer.startWatching();}// 第一步收集firstPids中进程的trace,超时会自动放弃// First collect all of the stacks of the most important pids.if (firstPids != null) {int num = firstPids.size();for (int i = 0; i < num; i++) {if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for pid "+ firstPids.get(i));final long timeTaken;if (useTombstonedForJavaTraces) {timeTaken = dumpJavaTracesTombstoned(firstPids.get(i), tracesFile, remainingTime);} else {timeTaken = observer.dumpWithTimeout(firstPids.get(i), remainingTime);}remainingTime -= timeTaken;if (remainingTime <= 0) {Slog.e(TAG, "Aborting stack trace dump (current firstPid=" + firstPids.get(i) +"); deadline exceeded.");return;}if (DEBUG_ANR) {Slog.d(TAG, "Done with pid " + firstPids.get(i) + " in " + timeTaken + "ms");}}}// 第二步收集nativePids中进程的trace,超时会自动放弃// Next collect the stacks of the native pidsif (nativePids != null) {for (int pid : nativePids) {if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native pid " + pid);final long nativeDumpTimeoutMs = Math.min(NATIVE_DUMP_TIMEOUT_MS, remainingTime);final long start = SystemClock.elapsedRealtime();Debug.dumpNativeBacktraceToFileTimeout(pid, tracesFile, (int) (nativeDumpTimeoutMs / 1000));final long timeTaken = SystemClock.elapsedRealtime() - start;remainingTime -= timeTaken;if (remainingTime <= 0) {Slog.e(TAG, "Aborting stack trace dump (current native pid=" + pid +"); deadline exceeded.");return;}if (DEBUG_ANR) {Slog.d(TAG, "Done with native pid " + pid + " in " + timeTaken + "ms");}}}//第三步收集extraPids中进程的trace,超时会自动放弃,这个代码和第一步一样的// Lastly, dump stacks for all extra PIDs from the CPU tracker.if (extraPids != null) {for (int pid : extraPids) {if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid " + pid);final long timeTaken;if (useTombstonedForJavaTraces) {timeTaken = dumpJavaTracesTombstoned(pid, tracesFile, remainingTime);} else {timeTaken = observer.dumpWithTimeout(pid, remainingTime);}remainingTime -= timeTaken;if (remainingTime <= 0) {Slog.e(TAG, "Aborting stack trace dump (current extra pid=" + pid +"); deadline exceeded.");return;}if (DEBUG_ANR) {Slog.d(TAG, "Done with extra pid " + pid + " in " + timeTaken + "ms");}}}} finally {if (observer != null) {observer.stopWatching();}}
}

总结下以上逻辑,firstPids和extraPids中的进程dump trace有两种方式,看useTombstonedForJavaTraces的取值;

如果useTombstonedForJavaTraces为真,采用dumpJavaTracesTombstoned获取trace
如果useTombstonedForJavaTraces为假,采用DumpStackFileObserver#dumpWithTimeout获取trace

对于nativePids中的进程,只能通过 Debug.dumpNativeBacktraceToFileTimeout来获取trace。

1. 利用am_anr来确定ANR的发生时间真的准确吗?
不一定准确,可能由于系统资源比较紧张造成一定程度的滞后,十多秒都可能,此时需要结合eventlog进一步分析。
2. ANR中经常出现没有trace,或者无效trace是怎么回事?
从appNotResponding方法中,我们看到有不少return的地方,在dumpStackTraces方法,也会有return出现,比如这么多进程的trace需要在20秒之内完成,在系统资源紧张的时候,能不能完成,是非常没有保障的;
3.有一些ANR问题需要binder对端的trace,通过上面的分析看,大概率是没有对端的trace的,除非binder call到system_server或者比较重要的几个native进程里面
4.发生ANR的时候,线程并没有暂停掉,有可能等到我们去抓这个进程的trace的时候,当前主线程耗时的方法都已经完成,恢复正常了,比如经常出现下面nativePollOnce状态的堆栈。
5. 我们需要通过源码可以发现,当发生的是后台进程ANR,会少收集很多的信息,比如CPU使用率,CPU占比较高的5个应用,NATIVE进程情况。当然同时更不会有弹窗出现,而是直接kill掉进程。但是这些情况也是我们必须要关心的,毕竟进程活着对于应用本身来说才有更多的可能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/43152.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Zabbix分布式监控

目录 分布式监控架构 实现分布式监控的步骤 优点和应用场景 安装Zabbix_Proxy Server端Web页面配置 测试 Zabbix 的分布式监控架构允许在大规模和地理上分散的环境中进行高效的监控。通过分布式监控&#xff0c;Zabbix 可以扩展其监控能力&#xff0c;支持大量主机和设备…

企业网站用免费wordpress主题的风险和弊端

免费WordPress主题除了不用花钱之外&#xff0c;几乎没有什么好处。个人网站如果用用还可以&#xff0c;如果是企业用的商业网站&#xff0c;最好不要用免费的WordPress主题模板&#xff0c;一但发生问题&#xff0c;你将付出的代价&#xff0c;比两三百元买个付费的WordPress主…

基于全志Orangepi Zero 2 的语音刷抖音项目

目录 一、硬件连接 二、项目实现功能 三、SU-03T语音模块的配置和烧录 3.1 创建产品&#xff1a; 3.2 设置PIN引脚为串口模式&#xff1a; 3.3 设置唤醒词&#xff1a; 3.4 设置指令语句&#xff1a; 3.5 设置控制详情&#xff1a; 3.6 发音人配置&#xff1a; 3.7 其…

atcoder 357 F Two Sequence Queries (线段树板子)

题目&#xff1a; 分析&#xff1a; 线段树 代码&#xff1a; // Problem: F - Two Sequence Queries // Contest: AtCoder - SuntoryProgrammingContest2024&#xff08;AtCoder Beginner Contest 357&#xff09; // URL: https://atcoder.jp/contests/abc357/tasks/abc357_…

华为HCIP Datacom H12-821 卷29

1.多选题 下面关于LSA age字段&#xff0c;描述正确的是∶ A、LSA age的单位为秒&#xff0c;在LSDB中的LSA的LS age随时间增长而增长 B、LSA age的单位为秒&#xff0c;在LSDB中的LSA的LS age随时间增长而减少 C、如果一条LSA的LS age达到了LS RefreshTime&#xff08…

[spring] Spring MVC - security(下)

[spring] Spring MVC - security&#xff08;下&#xff09; callback 一下&#xff0c;当前项目结构如下&#xff1a; 这里实现的功能是连接数据库&#xff0c;大范围和 [spring] rest api security 重合 数据库连接 - 明文密码 第一部分使用明文密码 设置数据库 主要就是…

内存与硬盘(笔记)

文章目录 1. 内存① 笔记② 相关软件 2. 硬盘① 笔记② 相关软件 3. 区别&#xff1a;4. 推荐 1. 内存 ① 笔记 ① 笔记本的内存条和台式机的内存条是不互通的 ② 我们常说的内存其实指的是运行内存(前台后台同时能运行多少APP) ③ 下图来自京东&#xff1a; 解析&#xff1…

应用程序提权

MYSQL提权 Mysql提权利用场景 1.拥有数据库账号密码 2.Webshell可以连接数据库&#xff0c;能够写文件 3.可操作数据库 如何获取数据库账号密码? 1.找数据库配置文件 2.通过webshell对数据库进行本地爆破 3.Hash获取mysql密码 UDF提权 udf提权指的是利用注…

ubuntu 分区情况

ubuntu系统安装与分区指南 - Philbert - 博客园 (cnblogs.com)https://www.cnblogs.com/liangxuran/p/14872811.html 详解安装Ubuntu Linux系统时硬盘分区最合理的方法-腾讯云开发者社区-腾讯云 (tencent.com)https://cloud.tencent.com/developer/article/1711884

pycharm中快捷键汇总

Pycarm指令汇总 Ctrl鼠标 单击&#xff0c;能直接查看其用法 Ctrl/ 快速注释 CtrlC 在pycharm的terminal中可以停止运行, 其他的地方可以复制。 CtrlV 粘贴 CtrlA 全选 CtrlP 查看&#xff08;&#xff09;中需要填写什么参数 Altenter 自动不补全所需要的库

终于找到了免费的C盘清理软件(极智C盘清理)

搜了很久&#xff0c;终于让我找到了一款 完全免费的C盘清理软件&#xff08;极智C盘清理&#xff09;。 点击前往官网免费使用极智C盘清理软件&#xff1a; C盘清理 用户好评 完全免费的极智C盘清理 用极智C盘清理清理了下系统的临时文件、缓存等无用数据文件&#xff0c;C盘终…

尚硅谷大事件后台API项目(学习自用)

大事件后台API项目 1.初始化 1.1创建项目 首先创建一个文件夹名为api_server&#xff0c;然后用vscode打开这个文件夹&#xff0c;新建终端&#xff0c;在终端输入npm init -y会生成一个package.json文件&#xff0c;接着新建一个文件app.js作为入口文件&#xff0c;在终端安…

哈尔滨等保测评标准的国际比较与启示

随着信息技术的快速发展和全球化趋势的加深&#xff0c;信息安全成为各国政府和企业共同关注的焦点。哈尔滨作为东北地区重要的经济和科技中心&#xff0c;其信息安全等级保护&#xff08;简称“等保”&#xff09;测评标准在确保本地企业信息安全的同时&#xff0c;也面临着与…

Could not find a package configuration file provided by “Torch“ 的参考解决方法

文章目录 写在前面一、问题描述二、解决方法参考链接 写在前面 自己的测试环境&#xff1a; Ubuntu20.04 一、问题描述 自己编译调用 Torch 的程序时&#xff0c;遇到如下报错&#xff1a; Make Error at CMakeLists.txt:15 (find_package):By not providing "FindTor…

设计资料:520-基于ZU15EG 适配AWR2243的雷达验证底板 高速信号处理板 AWR2243毫米波板

基于ZU15EG 适配AWR2243的雷达验证底板 一、板卡概述 本板卡系北京太速科技自主研发&#xff0c;基于MPSOC系列SOC XCZU15EG-FFVB1156架构&#xff0c;搭载两组64-bit DDR4&#xff0c;每组容量32Gb&#xff0c;最高可稳定运行在2400MT/s。另有1路10G SFP光纤接口、1路40G…

使用F1C200S从零制作掌机之构建debian文件系统

前情&#xff1a;使用buildrootfs构建的文件系统调试了很久NES模拟器&#xff0c;执行InfoNES模拟器的时候一直黑屏&#xff0c;无内容显示&#xff0c;调不通了&#xff0c;所以改用debian系统试试。 一、环境配置 首先下载两个工具&#xff1a;qemu-arm-static和debootstra…

uniapp小程序上传文件

需求 小程序需要上传用户相册图片或拍摄的照片到后端服务器 uniapp官方处理小程序文件方法 选择文件方法&#xff1a;uni.chooseMedia uni-app官网uni-app,uniCloud,serverless,uni.chooseVideo(OBJECT),chooseVideo HarmonyOS 兼容性,uni.chooseMedia(OBJECT),uni.saveVid…

Android:如何绘制View

点击查看Android 如何绘制视图官网 一、简介 Android 框架会在 Activity 获得焦点时请求 Activity 绘制其布局。Android 框架会处理绘制流程&#xff0c;但该 Activity 必须提供其布局层次结构的根节点。 Android 框架会绘制布局的根节点&#xff0c;并测量和绘制布局树。它会…

React@16.x(51)路由v5.x(16)- 手动实现文件目录参考

作为前面几篇文章的参考&#xff1a; 实现 Router实现 Route实现 Switch实现 withRouter实现 Link 和 NavLink 以上。

一.4 处理器读并解释储存在内存中的指令

此刻&#xff0c;hello.c源程序已经被编译系统翻译成了可执行目标文件hello&#xff0c;并被存放在硬盘上。要想在Unix系统上运行该可执行文件&#xff0c;我们将它的文件名输入到称为shell的应用程序中&#xff1a; linux>./hello hello, world linux> shell是一个命令…