对于黑盒可执行文件,您可以自动执行的最简单和最可靠的事情可能是查看它们的 CPU 使用率。当它们完成加载时,它们的所有线程应该(大部分)空闲,如果它们等待具有非无限超时的事件,可能会偶尔醒来。 (以及来自鼠标移动等其他 GUI 事件)。
确保等待足够长的时间来检测磁盘 I/O 上阻塞与等待用户输入阻塞之间的区别。 (在类 Unix 操作系统上,这是 Disk-sleep 和 Sleep 之间的区别,如 D 与 S 在诸如 top 的进程列表之类的东西中所示。)
如果您不想依赖操作系统来检测磁盘睡眠与常规睡眠,只需等待比最大磁盘 I/O 请求服务时间长几倍(~= 几倍磁盘延迟,更低如果被测进程是唯一执行 I/O 的进程)。如果黑盒进程在该时间间隔内没有使用任何 CPU 时间,您可以假设它已完成加载并正在屏幕上显示文件。
当然,正如@Ped7g 指出的那样,它可能没有解析整个文件。例如,当用户滚动浏览大型 PDF 时,它可能会按需延迟加载。在以编程方式向进程发送向下翻页命令后,观察 CPU 时间应该是检测进程何时完成更新的合理方法。
我认为您应该能够从中获得良好可靠的结果。如果您想可靠地确定进程已完成加载,而无需等待最坏的情况,您可能需要考虑多个输入(如系统 I/O 性能或未完成的磁盘 IO 请求)的启发式方法。
正如 cmets 中所讨论的,在文件描述符上寻找到达 EOF 的进程对于此目的并不可靠(它可能会映射它)。我会把它留在这里,以防它对任何人都有趣或有用,但为了您的使用,您可能希望完全忽略它。充其量,您可以将其用作启发式方法的输入,以决定进程何时完成加载。
在大多数操作系统上,进程都有一些工具可以跟踪其他进程。在 Linux 上,主要的是 ptrace API。像strace 这样的命令使用它来跟踪系统调用。我相信 Windows 也有类似的东西,我认为 OS X 也有。
因此您可以在 PDF 上查找 open() 系统调用以找到正确的 fd,然后在其上查找 mmap、read() 和 close() 系统调用。如果 read() 返回 0,则它位于 EOF。如果它在没有 mmap 的情况下关闭,则该过程已完成(除非它再次打开它,或出于某种原因使用 dup() 或 dup2())。
您可以解析 strace 的文本输出,或者自己使用 ptrace API。
或者,在 Linux 上,您可以查看 /proc/<PID>/fdinfo/<FD> 中的文件位置。其他操作系统可能有类似的工具来查看打开的文件描述符/文件句柄的文件位置。
例如,我碰巧打开了evince 显示一个PDF。在`/proc/
$ ll /proc/4241/fd
...
lr-x------ 1 peter peter 64 Oct 21 06:43 14 -> /f/p/docs/agner_fog.microarchitecture.pdf # is anyone really surprised this is the PDF I had open? :P
...
$ ls -lL /proc/4241/fd/14 # follow the symlink to see the file size
-rw-rw-r-- 1 peter peter 2078709 Feb 4 2016 /proc/4241/fd/14
$ m /proc/4241/fdinfo/14 # alias for less
pos: 2078709
flags: 0100000
mnt_id: 49
这证实了我的猜测,当 evince 完成读取文件时,文件位置将位于 EOF。您可能应该等待几毫秒并再次检查,以防被测软件再次循环文件。