背景:因为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);
}
}
由于HDFS小文件过多导致集群压力增大,项目改为将文件流以二进制形式存储。文章主要介绍如何不依赖APK路径,而是通过输入流直接获取APK的权限列表。思路是定位到APK中AndroidManifest.xml文件的部分,解析流内容以获取权限信息。
1332

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



