背景:因为HDFS小文件太多了 导致HDFS集群压力很大 所以项目由原来的存储文件方式改成了 把文件流以二进制的方式存入一个个大的文件块 通过文件 位置信息和偏移量信息来标记文件
网上很多通过APK路径 来获取APK的签名和权限列表的 但是直接对接流的基本没有 而且封装的方法 也没有好的可以接入流的接口
通过输入流获取APK权限列表:
思路:APK权限列表存在于APK的 AndroidManifest.xml 文件中 通过截取APK输入流中的
AndroidManifest.xml 文件流 解析xml文件 获取相关的权限列表
/** * DESC: 获取手机的apk安装包中用户权限列表 * @param filePath : 块文件路径 * @param position : APK文件所在块的位置 * @param filePath : APK文件偏移量 * */ public static List<String> getAPKUserPermitsByPosAndOffset(String filePath,long position, int offset){ getHDFS(); List<String> p_list= new ArrayList<String>(); Path path = new Path(filePath); FSDataInputStream dataStream; try { dataStream = hdfs.open(path); InputStream new_dataStream=getInputStreamByPosAndOffset(dataStream,position,offset); readAPkZipInputStream(new_dataStream,p_list); } catch (Exception e) { e.printStackTrace(); } return p_list; }
/** *@desc 获取HDFS文件流中 指定位置 指定偏移量的流 * */ private static InputStream getInputStreamByPosAndOffset(FSDataInputStream in,long position, int offset) { InputStream new_dataStream=null; try { byte[] btbuffer = new byte[offset]; in.read(position,btbuffer,0,offset);//read()方法从文件的指定position处读取之多为length字节的数据并存入缓冲区buffer的指定偏移量offset处. new_dataStream = new ByteArrayInputStream(btbuffer); } catch (Exception e) { if(offset<=0){ logger.error("offset非法.....",e); }else{ logger.error("HDFS文件指定偏移量长度的流获取失败.....",e); } } return new_dataStream; }
/** * DESC: 读取APK文件输入流 获得权限列表 * @param inputStream : APK文件输入流,p_list: * @param p_list : 返回结果 * */ public static void readAPkZipInputStream(InputStream inputStream,List<String> p_list) throws Exception { InputStream in = new BufferedInputStream(inputStream); ZipInputStream zin = new ZipInputStream(in); ZipEntry ze; try { while ((ze = zin.getNextEntry()) != null) { if (ze.isDirectory()) { } else { if("AndroidManifest.xml".equals(ze.getName())){ //找到AndroidManifest.xml文件 long size = ze.getSize(); if (size > 0) { parseAndroidManifestByInputStream(zin,p_list); } } } } } catch (Exception e) { logger.error("解析AndroidManifest.xml流失败...",e); } finally { zin.closeEntry(); inputStream.close(); in.close(); zin.close(); } }
/** * 解析 根据AndroidManifest.xml文件流 获取用户权限列表 */ public static void parseAndroidManifestByInputStream(ZipInputStream fileInputStream,List<String> p_list) { try { AXmlResourceParser parser = new AXmlResourceParser(); parser.open(fileInputStream); StringBuilder indent = new StringBuilder(10); while (true) { int type = parser.next(); if (type == XmlPullParser.END_DOCUMENT) { break; } switch (type) { case XmlPullParser.START_DOCUMENT: break; case XmlPullParser.START_TAG: int namespaceCountBefore = parser.getNamespaceCount(parser.getDepth() - 1); int namespaceCount = parser.getNamespaceCount(parser.getDepth()); for (int i = namespaceCountBefore; i != namespaceCount; ++i) { // System.out.printf("%sxmlns:%s=\"%s\"", // indent, // parser.getNamespacePrefix(i), // parser.getNamespaceUri(i)); // System.out.println(); } for (int i = 0; i != parser.getAttributeCount(); ++i) { // System.out.printf("%s%s%s=\"%s\"", // indent, // getNamespacePrefix(parser.getAttributePrefix(i)), // parser.getAttributeName(i), // getAttributeValue(parser, i)); // System.out.println(); if(getAttributeValue(parser, i).contains("android.permission")){ p_list.add(getAttributeValue(parser, i)); } // System.out.println(getAttributeValue(parser, i)); } break; case XmlPullParser.END_TAG: break; case XmlPullParser.TEXT: // System.out.printf("%s%s", // indent, // parser.getText()); // System.out.println(); default: break; } } } catch (Exception e) { logger.error("解析AndroidManifest.xml流中的权限列表失败...",e); } }