赞
踩
当我们使用Android Studio 搜索 MainActivity 的时候可以查到内容,好像看起来很方便?
但是如果关键字在class文件中,那么就搜索不到了。
我们App上线之后发现用户使用流量猛增,使用各种统计手段发现程序大量创建一个名为 “xxx” (因为避免涉密不具体贴出来字符,可以看上面图片中的字符串)的线程,这个线程是谁创建的? 我们上来先搜索这个"xxx"发现我们的代码中并没有创建过这个线程,那么是谁创建的呢?
怀疑是什么aar导致的,于是我们要排查到底是哪个aar导致的呢?
注意是使用Android Studio 运行 Java项目,不知道怎么运行java项目可以看Android Studio运行JAVA程序
public class Grep { public static final String GRADLE_CACHE_PATH = "/Users/liangchaojie/.gradle/caches/transforms-1/files-1.1"; public static final String TARGET_PATH = "/Users/liangchaojie/Desktop/result"; private static int mCopyCount = 0; private static int mUnZipCount = 0; private static int mDeleteCount = 0; public static void main(String[] args) { File file = new File(GRADLE_CACHE_PATH); // 1 先把缓存中的文件拷贝到指定的文件夹中 traverseCopy(file); System.out.println("traverseCopy file number ="+mCopyCount); // 2 把所有的jar文件解压出来到指定的文件夹中 tarJarFile(TARGET_PATH); // 3 删除掉之前存在的jar文件 deleteJarFile(TARGET_PATH); } /** * 遍历复制gradle cache 中的classes.jar到 指定目录中去 * * @param file */ private static void traverseCopy(File file) { File[] fs = file.listFiles(); for (File f : fs) { if (f.isDirectory()) //若是目录,则递归打印该目录下的文件 { traverseCopy(f); } else if (f.isFile() && "classes.jar".equals(f.getName())) //若是文件,直接打印 { mCopyCount++; String sourcePath = f.getAbsolutePath(); String aarName = getSimpleAarPathName(f.getAbsolutePath()); String targetPath = getTargetPathName(aarName); File fileTargetFile = new File(targetPath); // 如果文件已经存在就不用去拷贝了 if(fileTargetFile.exists()){ continue; } copyFile(sourcePath, targetPath); } } } /** * 返回类似 homepage-api-2.5.30 * @param path * @return */ private static String getSimpleAarPathName(String path) { String aarNameFirst = path.substring(path.indexOf("files-1.1/") + 10, path.indexOf(".aar/")); String aarNameLast = path.substring(path.indexOf(".aar/") + 5, path.indexOf(".aar/") + 10); return aarNameFirst+"-"+aarNameLast; } private static String getTargetPathName(String aarName) { return TARGET_PATH + "/" + aarName +".jar"; } public static void copyFile(String source, String target) { try (FileInputStream fis = new FileInputStream(new File(source)); FileOutputStream fos = new FileOutputStream(new File(target))) { FileChannel sourceChannel = fis.getChannel(); FileChannel targetChannel = fos.getChannel(); MappedByteBuffer mappedByteBuffer = sourceChannel.map(FileChannel.MapMode.READ_ONLY, 0, sourceChannel.size()); targetChannel.write(mappedByteBuffer); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private static void deleteJarFile(String targetPath) { File[] fs = new File(targetPath).listFiles(); for (File f : fs) { if (f.isFile() && f.getName().contains(".jar")) { mDeleteCount++; f.delete(); } } System.out.println(" deleteJarFile file number = " + mDeleteCount); } /** * 把指定目录中的 classes.jar 解压到文件中 */ private static void tarJarFile(String targetPath) { File[] fs = new File(targetPath).listFiles(); for (File f : fs) { if (f.isFile() && f.getName().contains(".jar")) { mUnZipCount++; String directory = f.getName().substring(0, f.getName().lastIndexOf(".jar")); String targetPathDirectory = TARGET_PATH + "/" + directory + "/"; File targetPathDirectoryFile = new File(targetPathDirectory); // 如果已经创建过文件夹就不要去重复创建了 if (targetPathDirectoryFile.exists()) { continue; } targetPathDirectoryFile.mkdirs(); UnZipUtils.unZip(f, targetPathDirectory); } } System.out.println(" tarJarFile file number = " + mUnZipCount); } }
/** * 对文件进行解压操作 */ public class UnZipUtils { private static final int BUFFER_SIZE = 2 * 1024; /** * zip解压 * @param srcFile zip源文件 * @param destDirPath 解压后的目标文件夹 * @throws RuntimeException 解压失败会抛出运行时异常 */ public static void unZip(File srcFile, String destDirPath) throws RuntimeException { long start = System.currentTimeMillis(); // 判断源文件是否存在 if (!srcFile.exists()) { throw new RuntimeException(srcFile.getPath() + "所指文件不存在"); } // 开始解压 ZipFile zipFile = null; try { zipFile = new ZipFile(srcFile); Enumeration<?> entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = (ZipEntry) entries.nextElement(); // 如果是文件夹,就创建个文件夹 if (entry.isDirectory()) { String dirPath = destDirPath + "/" + entry.getName(); File dir = new File(dirPath); dir.mkdirs(); } else { // 如果是文件,就先创建一个文件,然后用io流把内容copy过去 File targetFile = new File(destDirPath + "/" + entry.getName()); // 保证这个文件的父文件夹必须要存在 if(!targetFile.getParentFile().exists()){ targetFile.getParentFile().mkdirs(); } targetFile.createNewFile(); // 将压缩文件内容写入到这个文件中 InputStream is = zipFile.getInputStream(entry); FileOutputStream fos = new FileOutputStream(targetFile); int len; byte[] buf = new byte[BUFFER_SIZE]; while ((len = is.read(buf)) != -1) { fos.write(buf, 0, len); } // 关流顺序,先打开的后关闭 fos.close(); is.close(); } } long end = System.currentTimeMillis(); } catch (Exception e) { throw new RuntimeException("unzip error from ZipUtils", e); } finally { if(zipFile != null){ try { zipFile.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
grep "xxx" -r /Users/liangchaojie/Desktop/result
用Android Studio打开这个a.class,确实发现创建了线程
完结撒花~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。