开发环境
Android 9
前提及重点
打印应用程序进程占用的文件资源
public class FdInfo {
public static class Node {
Node(int fd, String path) {
this.fd = fd;
this.path = path;
}
@Override
public String toString() {
return fd + "--->" + path;
}
public int fd;
public String path;
}
public static List<Node> getFdList() {
int pid = android.os.Process.myPid();
String fdPath = "/proc/" + pid + "/fd";
List<Node> fdList = new ArrayList<>();
File fdDir = new File(fdPath);
if (fdDir.exists() && fdDir.canRead()) {
String[] filePath = fdDir.list();
if (null != filePath) {
for (String temp : filePath) {
File subFile = new File(fdPath + File.separator + temp);
try {
fdList.add(new Node(Integer.parseInt(subFile.getName()), subFile.getCanonicalPath()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return fdList;
}
}
过滤出u盘路径下的文件占用
// uPath为u盘的根路径
public class IoUtils {
public static void list(String uPath) {
log("============ list start ============");
List<FdInfo.Node> nodeList = FdInfo.getFdList();
if (nodeList.size() > 0) {
for (FdInfo.Node Node : nodeList) {
if (Node.path.startsWith(uPath)) {
log("文件占用:" + Node);
}
}
nodeList.clear();
}
log("============ list end ============");
}
private static void log(String text) {
Log.d("apk_manager", text);
}
}
此代码为本篇核心,问题的解决围绕于它。
问题1
调用PackageManager#getPackageArchiveInfo(String archiveFilePath, int flags)查看完u盘apk文件信息,拔掉u盘,崩溃
String uPath = "/storage/usb1-1-2-p4";
String apkPath = uPath + "/android_apps/test0.apk";
File appsFile = new File(apkPath);
log("解析apk文件:" + appsFile.getAbsolutePath());
AppInfo appInfo = new AppInfo();
appInfo.path = appsFile.getAbsolutePath();
appInfo.fileName = appsFile.getName();
log("获取包管理器");
PackageManager pm = getPackageManager();
log("获取包信息");
IoUtils.list(uPath);
PackageInfo usbPackageInfo = pm.getPackageArchiveInfo(appInfo.path, PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES);
IoUtils.list(uPath);
日志(精简过的)
023-05-22 18:13:01.971 14191-14191 apk_manager pid-14191 D usb插入:
2023-05-22 18:13:03.849 14191-14191 apk_manager pid-14191 D usb装载:
2023-05-22 18:13:06.352 14191-14414 apk_manager pid-14191 D 解析apk文件:/storage/usb1-1-2-p4/android_apps/test0.apk
2023-05-22 18:13:06.353 14191-14414 apk_manager pid-14191 D 获取包管理器
2023-05-22 18:13:06.353 14191-14414 apk_manager pid-14191 D 获取包信息
2023-05-22 18:13:06.356 14191-14414 apk_manager pid-14191 D ============ list start ============
2023-05-22 18:13:06.399 14191-14414 apk_manager pid-14191 D ============ list end ============
2023-05-22 18:13:06.476 14191-14414 apk_manager pid-14191 D ============ list start ============
2023-05-22 18:13:06.489 14191-14414 apk_manager pid-14191 D 文件占用:62--->/storage/usb1-1-2-p4/android_apps/test0.apk
2023-05-22 18:13:06.489 14191-14414 apk_manager pid-14191 D 文件占用:70--->/storage/usb1-1-2-p4/android_apps/test0.apk
2023-05-22 18:13:06.489 14191-14414 apk_manager pid-14191 D ============ list end ============
2023-05-22 18:13:10.062 14191-14191 apk_manager pid-14191 D usb拔出:
2023-05-22 18:13:11.619 457-459 vold vold W Found symlink /proc/14191/fd/62 referencing /storage/usb1-1-2-p4/android_apps/test0.apk
2023-05-22 18:13:11.619 457-459 vold vold W Found symlink /proc/14191/fd/70 referencing /storage/usb1-1-2-p4/android_apps/test0.apk
2023-05-22 18:13:11.620 457-459 vold vold W Sending Interrupt to 14191
2023-05-22 18:13:11.719 1272-1528 InputDispatcher system_server E channel '90ed54 com.test.u/com.xxx.xxx.AppActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
2023-05-22 18:13:18.803 14434-14434 apk_manager com.test.u D usb卸载:
这里可以看到,对同一个文件,这个方法产生了两个占用。查看过PackageManager#getPackageArchiveInfo() FrameWork层的代码,发现资源都有通过 libcore.io.IoUtils.closeQuietly(assetLoader); 进行释放,但是释放完都没有解除占用。我用反射模拟模拟了加载的过程,d 模拟的过程中,我萌生了一个想法,我想看看调用完closeQuietly()到底过多久会释放,这个想法造就了这篇文章。我在调用PackageManager#getPackageArchiveInfo()后,执行下面的代码
new Thread(new Runnable() {
@Override
public void run() {
while (true){
IoUtils.list(uPath);
SystemClock.sleep(100);
}
}
}).start();
日志:
2023-05-22 18:52:03.040 17896-18371 apk_manager com.test.u D 解析apk文件:/storage/usb1-1-2-p4/android_apps/test0.apk
2023-05-22 18:52:03.042 17896-18371 apk_manager com.test.u D 获取包管理器
2023-05-22 18:52:03.042 17896-18371 apk_manager com.test.u D 获取包信息
2023-05-22 18:52:03.044 17896-18371 apk_manager com.test.u D ============ list start ============
2023-05-22 18:52:03.045 17896-17896 Thread-2 com.test.u I type=1400 audit(0.0:8159): avc: denied { getattr } for path="/sys/kernel/debug/tracing/trace_marker" dev="tracefs" ino=6068 scontext=u:r:system_app:s0 tcontext=u:object_r:debugfs_trace_marker:s0 tclass=file permissive=1
2023-05-22 18:52:03.072 17896-18371 apk_manager com.test.u D ============ list end ============
2023-05-22 18:52:03.148 17896-18373 apk_manager com.test.u D ============ list start ============
2023-05-22 18:52:03.173 17896-18373 apk_manager com.test.u D 文件占用:62--->/storage/usb1-1-2-p4/android_apps/test0.apk
2023-05-22 18:52:03.173 17896-18373 apk_manager com.test.u D 文件占用:68--->/storage/usb1-1-2-p4/android_apps/test0.apk
2023-05-22 18:52:03.173 17896-18373 apk_manager com.test.u D ============ list end ============
......
2023-05-22 18:52:05.133 17896-18373 apk_manager com.test.u D ============ list start ============
2023-05-22 18:52:05.143 17896-18373 apk_manager com.test.u D 文件占用:62--->/storage/usb1-1-2-p4/android_apps/test0.apk
2023-05-22 18:52:05.144 17896-18373 apk_manager com.test.u D 文件占用:68--->/storage/usb1-1-2-p4/android_apps/test0.apk
2023-05-22 18:52:05.144 17896-18373 apk_manager com.test.u D ============ list end ============
2023-05-22 18:52:05.244 17896-18373 apk_manager com.test.u D ============ list start ============
2023-05-22 18:52:05.262 17896-18373 apk_manager com.test.u D ============ list end ============
上面日志打印太多,做了下精简,我们看到经过大概2秒左右的循环调用,占用被解除了,这个时间有长有短,甚至有调用一次就能释放的,这时候拔u盘就不再崩溃。但是如果你把循环打印的代码注掉,不要这个打印这个过程,即使经过10多秒,拔u盘照样会崩溃。所以我们可以把它做为一个释放占用的方法来使用。使用时需要一些技巧和统筹来替代无限循环和对线程进行管理。
题外话:发现这个方法的时,我的感觉像是哔了dog。
释放的工具类
根据问题1中得到的释放方式,我做了个工具类
public class IoUtils {
private static class LoopThread extends Thread {
// 新添加的,需要记录
static int WHAT_ADD = 0;
// 非新添加,进行中的,不需要记录
static int WHAT_LAST = 1;
public Handler handler;
private final HashMap<String, List<FdInfo.Node>> pathNoReleaseMap = new HashMap<>();
private Runnable delayAction;
@Override
public void run() {
Looper.prepare();
handler = new Handler(Looper.myLooper()) {
@Override
public void handleMessage(Message msg) {
String uPath = (String) msg.obj;
pathNoReleaseMap.put(uPath, new ArrayList<>());
if (msg.what == WHAT_ADD && delayAction != null) {
// 如果有待执行,将uPath放入后,等待待执行,防止 WHAT_ADD 调用多次,创建多个待执行
return;
}
if (delayAction != null) {
// 如果是待执行,将待执行置空,执行一次
delayAction = null;
}
// 只要 pathNoReleaseMap 有值,说明还需要继续释放, 创建新的待执行
delayAction = new Runnable() {
@Override
public void run() {
IoUtils.requestNoRelease(pathNoReleaseMap);
for (Map.Entry<String, List<FdInfo.Node>> item : pathNoReleaseMap.entrySet()) {
String itemPath = item.getKey();
List<FdInfo.Node> noReleaseList = item.getValue();
if (noReleaseList == null || noReleaseList.size() == 0) {
// 1.释放完成,需要从记录中移除
pathNoReleaseMap.remove(itemPath);
}
}
if (pathNoReleaseMap.keySet().size() > 0) {
Message message = handler.obtainMessage(LoopThread.WHAT_LAST);
message.obj = uPath;
handler.sendMessage(message);
}
}
};
handler.postDelayed(delayAction, 100);
}
};
Looper.loop();
}
}
private static final LoopThread loopThread = new LoopThread();
static {
loopThread.start();
}
/**
* 释放占用的u盘文件
*
* @param uPath u盘路径
*/
public static void release(String uPath) {
Handler threadHandler = loopThread.handler;
if (threadHandler != null) {
Message message = threadHandler.obtainMessage(LoopThread.WHAT_ADD);
message.obj = uPath;
threadHandler.sendMessage(message);
}
}
private static void requestNoRelease(HashMap<String, List<FdInfo.Node>> pathNoReleaseMap) {
log("============ list start ============");
List<FdInfo.Node> nodeList = FdInfo.getFdList();
if (nodeList.size() > 0) {
for (FdInfo.Node node : nodeList) {
addMapElement(pathNoReleaseMap, node);
}
nodeList.clear();
}
log("============ list end ============");
}
private static void addMapElement(HashMap<String, List<FdInfo.Node>> pathNoReleaseMap, FdInfo.Node node) {
for (Map.Entry<String, List<FdInfo.Node>> entry : pathNoReleaseMap.entrySet()) {
if (isInUPath(entry.getKey(), node.path)) {
log("文件占用" + node);
entry.getValue().add(node);
}
}
}
private static boolean isInUPath(String uPath, String filePath) {
return !TextUtils.isEmpty(uPath) && !TextUtils.isEmpty(filePath) && filePath.startsWith(uPath);
}
private static void log(String text) {
Log.d("apk_manager", text);
}
@SuppressWarnings("deprecation")
@SuppressLint("UseCompatLoadingForDrawables")
public static void readInfo(Context context, String apkPath, AppInfo appInfo, ApplicationInfo applicationInfo) {
AssetManager assetManager = createAssetManager(apkPath);
Resources resources = new Resources(assetManager, context.getResources().getDisplayMetrics(), context.getResources().getConfiguration());
appInfo.name = resources.getString(applicationInfo.labelRes);
appInfo.icon = resources.getDrawable(applicationInfo.icon);
if (assetManager != null) {
assetManager.close();
}
}
//利用反射调用AssetManager的addAssetPath()方法
private static AssetManager createAssetManager(String apkPath) {
try {
AssetManager assetManager = AssetManager.class.newInstance();
AssetManager.class.getDeclaredMethod("addAssetPath", String.class).invoke(
assetManager, apkPath);
return assetManager;
} catch (Throwable th) {
th.printStackTrace();
}
return null;
}
}
其中也包含网上翻找到的加载icon的方法,AppInfo是我自定义的保存信息的类
问题2 读取apk Icon ,释放后程序会崩溃
遇到了新的问题,为了解决问题1,我网上看过好博客,但基本都是解决读取icon后,拔u盘崩溃的,所以这步,我上来就用网上现有的AssetManager读取后close掉的解决方式,方法可用但是有问题,方法已经放在上面的工具类中,发现问题也很偶然,发现后各种找原因,最后还是定位到了原因,并找到了解决方法。
我在安卓内置存储中放apk包读取试了下,也会崩溃,而调用我们的释放会让这个过程提前。当然并非所有的apk都有这个问题,原因见下。
日志:
2023-05-23 09:32:41.324 5834-5843 libc com.test.u A FORTIFY: pthread_mutex_destroy called on a destroyed mutex (0x7bf25f7ac0)
2023-05-23 09:32:41.325 5834-5843 libc com.test.u A Fatal signal 6 (SIGABRT), code -6 (SI_TKILL) in tid 5843 (FinalizerDaemon), pid 5834 (com.test.u)
2023-05-23 09:32:41.405 5917-5917 DEBUG pid-5917 A *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
2023-05-23 09:32:41.405 5917-5917 DEBUG pid-5917 A Build fingerprint: 'Android/msm8953_64/msm8953_64:9/PKQ1.181105.001/pansiyuan04121703:user/test-keys'
2023-05-23 09:32:41.405 5917-5917 DEBUG pid-5917 A Revision: '0'
2023-05-23 09:32:41.405 5917-5917 DEBUG pid-5917 A ABI: 'arm64'
2023-05-23 09:32:41.405 5917-5917 DEBUG pid-5917 A pid: 5834, tid: 5843, name: FinalizerDaemon >>> com.test.u <<<
2023-05-23 09:32:41.405 5917-5917 DEBUG pid-5917 A signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
2023-05-23 09:32:41.406 5917-5917 DEBUG pid-5917 A Abort message: 'FORTIFY: pthread_mutex_destroy called on a destroyed mutex (0x7bf25f7ac0)'
2023-05-23 09:32:41.406 5917-5917 DEBUG pid-5917 A x0 0000000000000000 x1 00000000000016d3 x2 0000000000000006 x3 0000000000000008
2023-05-23 09:32:41.406 5917-5917 DEBUG pid-5917 A x4 0000000000000000 x5 0000000000000000 x6 0000000000000000 x7 0000000000000010
2023-05-23 09:32:41.406 5917-5917 DEBUG pid-5917 A x8 0000000000000083 x9 2d8023c7cffd8873 x10 0000000000000000 x11 fffffffc7ffffbdf
2023-05-23 09:32:41.406 5917-5917 DEBUG pid-5917 A x12 0000000000000001 x13 00000000646c17b9 x14 0012897a9f355600 x15 0000d218ca3ea7c7
2023-05-23 09:32:41.406 5917-5917 DEBUG pid-5917 A x16 0000007c7cc642c0 x17 0000007c7cb959d0 x18 0000000000000000 x19 00000000000016ca
2023-05-23 09:32:41.407 5917-5917 DEBUG pid-5917 A x20 00000000000016d3 x21 0000007bf2550400 x22 0000007be36451c0 x23 000000007375a7e0
2023-05-23 09:32:41.407 5917-5917 DEBUG pid-5917 A x24 0000000000000008 x25 0000007be3647588 x26 0000007bf25504a0 x27 0000000000000002
2023-05-23 09:32:41.407 5917-5917 DEBUG pid-5917 A x28 0000000000000000 x29 0000007be3644d70
2023-05-23 09:32:41.407 5917-5917 DEBUG pid-5917 A sp 0000007be3644d30 lr 0000007c7cb87004 pc 0000007c7cb8702c
2023-05-23 09:32:41.697 5917-5917 DEBUG pid-5917 A
backtrace:
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #00 pc 000000000002202c /system/lib64/libc.so (abort+116)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #01 pc 00000000000935ec /system/lib64/libc.so (__fortify_fatal(char const*, ...)+120)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #02 pc 0000000000092c54 /system/lib64/libc.so (HandleUsingDestroyedMutex(pthread_mutex_t*, char const*)+52)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #03 pc 0000000000093560 /system/lib64/libc.so (pthread_mutex_destroy+148)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #04 pc 00000000000acfd0 /system/lib64/libc++.so (std::__1::mutex::~mutex()+8)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #05 pc 000000000012f23c /system/lib64/libandroid_runtime.so (android::NativeDestroy(_JNIEnv*, _jclass*, long)+104)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #06 pc 00000000003cf278 /system/framework/arm64/boot-framework.oat (offset 0x3ce000) (android.app.backup.BackupDataInput.dtor [DEDUPED]+152)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #07 pc 000000000055544c /system/lib64/libart.so (art_quick_invoke_static_stub+604)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #08 pc 00000000000cf6e8 /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+232)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #09 pc 000000000027f2b4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*)+344)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #10 pc 00000000002792bc /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+968)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #11 pc 0000000000525cc4 /system/lib64/libart.so (MterpInvokeStatic+204)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #12 pc 0000000000547914 /system/lib64/libart.so (ExecuteMterpImpl+14612)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #13 pc 0000000000564042 /system/framework/boot-framework.vdex (android.content.res.AssetManager.decRefsLocked+40)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #14 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3783761849+488)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #15 pc 0000000000258ab4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #16 pc 00000000002792a0 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+940)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #17 pc 0000000000525b00 /system/lib64/libart.so (MterpInvokeDirect+296)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #18 pc 0000000000547894 /system/lib64/libart.so (ExecuteMterpImpl+14484)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #19 pc 000000000041c04c /system/framework/boot-framework.vdex (android.content.res.AssetManager.xmlBlockGone+4)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #20 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3783761849+488)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #21 pc 0000000000258ab4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #22 pc 00000000002792a0 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+940)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #23 pc 0000000000527804 /system/lib64/libart.so (MterpInvokeVirtualQuick+584)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #24 pc 000000000054b514 /system/lib64/libart.so (ExecuteMterpImpl+29972)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #25 pc 00000000005665a2 /system/framework/boot-framework.vdex (android.content.res.XmlBlock.decOpenCountLocked+50)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #26 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3783761849+488)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #27 pc 0000000000258ab4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #28 pc 00000000002792a0 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+940)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #29 pc 0000000000525b00 /system/lib64/libart.so (MterpInvokeDirect+296)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #30 pc 0000000000547894 /system/lib64/libart.so (ExecuteMterpImpl+14484)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #31 pc 0000000000425734 /system/framework/boot-framework.vdex (android.content.res.XmlBlock.close+16)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #32 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3783761849+488)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #33 pc 0000000000258ab4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #34 pc 00000000002792a0 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+940)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #35 pc 00000000005247c0 /system/lib64/libart.so (MterpInvokeVirtual+588)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #36 pc 0000000000547794 /system/lib64/libart.so (ExecuteMterpImpl+14228)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #37 pc 0000000000425754 /system/framework/boot-framework.vdex (android.content.res.XmlBlock.finalize)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #38 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3783761849+488)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #39 pc 0000000000258ab4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #40 pc 00000000002792a0 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+940)
2023-05-23 09:32:41.698 5917-5917 DEBUG pid-5917 A #41 pc 00000000005247c0 /system/lib64/libart.so (MterpInvokeVirtual+588)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #42 pc 0000000000547794 /system/lib64/libart.so (ExecuteMterpImpl+14228)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #43 pc 00000000000aec98 /system/framework/boot-core-libart.vdex (java.lang.Daemons$FinalizerDaemon.doFinalize+22)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #44 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3783761849+488)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #45 pc 0000000000258ab4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #46 pc 00000000002792a0 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+940)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #47 pc 0000000000525b00 /system/lib64/libart.so (MterpInvokeDirect+296)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #48 pc 0000000000547894 /system/lib64/libart.so (ExecuteMterpImpl+14484)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #49 pc 00000000000aed80 /system/framework/boot-core-libart.vdex (java.lang.Daemons$FinalizerDaemon.runInternal+164)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #50 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3783761849+488)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #51 pc 0000000000258ab4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #52 pc 00000000002792a0 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+940)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #53 pc 00000000005247c0 /system/lib64/libart.so (MterpInvokeVirtual+588)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #54 pc 0000000000547794 /system/lib64/libart.so (ExecuteMterpImpl+14228)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #55 pc 00000000000aeb78 /system/framework/boot-core-libart.vdex (java.lang.Daemons$Daemon.run+20)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #56 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3783761849+488)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #57 pc 0000000000258ab4 /system/lib64/libart.so (art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+216)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #58 pc 00000000002792a0 /system/lib64/libart.so (bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+940)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #59 pc 000000000052573c /system/lib64/libart.so (MterpInvokeInterface+1392)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #60 pc 0000000000547994 /system/lib64/libart.so (ExecuteMterpImpl+14740)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #61 pc 00000000000ca876 /system/framework/boot-core-oj.vdex (java.lang.Thread.run+12)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #62 pc 0000000000252fc0 /system/lib64/libart.so (_ZN3art11interpreterL7ExecuteEPNS_6ThreadERKNS_20CodeItemDataAccessorERNS_11ShadowFrameENS_6JValueEb.llvm.3783761849+488)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #63 pc 0000000000515054 /system/lib64/libart.so (artQuickToInterpreterBridge+1020)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #64 pc 000000000055e2fc /system/lib64/libart.so (art_quick_to_interpreter_bridge+92)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #65 pc 0000000000555188 /system/lib64/libart.so (art_quick_invoke_stub+584)
2023-05-23 09:32:41.699 5917-5917 DEBUG pid-5917 A #66 pc 00000000000cf6c8 /system/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+200)
2023-05-23 09:32:41.700 5917-5917 DEBUG pid-5917 A #67 pc 000000000045c8f0 /system/lib64/libart.so (art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char const*)+104)
2023-05-23 09:32:41.700 5917-5917 DEBUG pid-5917 A #68 pc 000000000045d9ac /system/lib64/libart.so (art::InvokeVirtualOrInterfaceWithJValues(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jmethodID*, jvalue*)+424)
2023-05-23 09:32:41.700 5917-5917 DEBUG pid-5917 A #69 pc 0000000000488848 /system/lib64/libart.so (art::Thread::CreateCallback(void*)+1120)
2023-05-23 09:32:41.700 5917-5917 DEBUG pid-5917 A #70 pc 0000000000091f2c /system/lib64/libc.so (__pthread_start(void*)+36)
2023-05-23 09:32:41.700 5917-5917 DEBUG pid-5917 A #71 pc 00000000000238e8 /system/lib64/libc.so (__start_thread+68)
2023-05-23 09:32:42.200 1257-1529 InputDispatcher system_server E channel '7a47b3d com.test.u/com.xxx.xxx.AppActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
发现过程
我有自己开发程序的源码,也有系统开发都那里拿到了一些上层应用的源码,用来调整界面UI。出问题的是系统开发提供的源码编译出来的apk。同一个编译器,我自己的程序编译的apk,没有问题。系统开发提供的源码编译出的apk,读取完icon后,使用问题1中发现的释放占用的方法,会崩溃。
定位原因
经过各种折腾后,终于还是定位到了问题产生的原因 ,在源码的资源目录下存在:
res
– mipmap-anydpi-v26
---- ic_launcher.xml
并且在清单文件中配置应用图标时使用的是:
android:icon="@mipmap/ic_launcher"
这个资源xml图片资源文件是产生问题的罪魁祸首,删掉后可正常读取,但你只能对自己编译的apk能这么干,不能限制别人这么用,所以这不是最终解决方法。
解决方法:
我在漫漫折腾中找到一个非常简单直接的解决方式。你可能想不到,答案近在手边 。
在发现并定位问题,我产生一个猜测,调用了 assetManager.close(); 后,只是让它可以被释放,但遇到xml图片的时候,内部的流操作并未停止,当系统把文件占用释放时,流操作就出现了问题,基于这个猜测,我寻找着终止流操作的办法,最后在查看 Resources 方法的时候,找到两个看着可能有用的方法:
resources.flushLayoutCache();
resources.finishPreloading();
抱着试一试的态度,我把它们放在读取图片之后,果然不再出现错误,最后确定是 resources.flushLayoutCache(); 发挥了作用,所以上面的工具类,应在读取读取完图片后加上这行代码;
appInfo.icon = resources.getDrawable(applicationInfo.icon);
resources.flushLayoutCache();
这样就不会在读取完图片后出现崩溃了。
未整理部分
3.新的问题,读取多个apk信息后立刻拔掉u盘,因为问题1中的释放方式不是立即释放的,有短暂的延迟时间,通常在几百毫秒,系统赶在释放未完全时,检测文件文件占用情况,这时会导致程序崩溃。
解决思路:之前在解决1时曾在网上看到过,系统在关闭进程时会发送信号,我们的应用程序可通过jni对系统终结信号拦截,我通过将代码植入我的程序,发现拦截后会系统会给大概5,6秒的缓冲时间,这期间如果什么都不做,系统会再次检测,发现还有文件占用,会再改善结束信号,此次信号会直接杀死进程。之前没有发现问题1中的释放方式,所以这个方法就被放置了,但这个5,6秒的缓冲时间对我们释放占用是不是很搭配,于是我便猜测释放完后系统不会再发送终结信号。
测试方法:注释掉代码中调用释放占用的地方,在拦截到信号后,再调用释放,观察系统是否会继续终结进程,如果不终结,并且重复验证都如此,说明我的猜测是正确的。
验证结果: 猜测成立,信号拦截可以做为兜底操作,可以防止上面的情形导致的程序崩溃。
有人就要说了,既然这里可以释放掉,为什么不统一在这里释放:因为进程占用文件若不及时释放,肯定会增加内存和性能上的开销,所以读取到需要信息就后应及时释放,这里的释放只做为兜底的保险。
另外,这个信号只在人拔u盘后,在系统检测时,占用文件没有释放完,系统才会发出,如果系统检测时,已经释放完,系统是不会发信号的,这时拔u盘也不会崩溃,我们也不需要再处理。
又发现新问题,有的资源在接收到信号后并不能及时释放掉,或者在拔掉又快速插入,也会出现问题

972

被折叠的 条评论
为什么被折叠?



