DexParser Java part
This commit is contained in:
parent
702c10eff4
commit
a691abc510
|
|
@ -39,6 +39,7 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.lsposed.lspd.core.BuildConfig;
|
||||
import org.lsposed.lspd.impl.utils.LSPosedDexParser;
|
||||
import org.lsposed.lspd.models.Module;
|
||||
import org.lsposed.lspd.nativebridge.HookBridge;
|
||||
import org.lsposed.lspd.service.ILSPInjectedModuleService;
|
||||
|
|
@ -901,6 +902,6 @@ public class LSPosedContext extends XposedContext {
|
|||
@Nullable
|
||||
@Override
|
||||
public DexParser parseDex(ByteBuffer dexData) throws IOException {
|
||||
return null;
|
||||
return new LSPosedDexParser(dexData);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,752 @@
|
|||
package org.lsposed.lspd.impl.utils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.lsposed.lspd.nativebridge.DexParserBridge;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import io.github.libxposed.util.DexParser;
|
||||
|
||||
public class LSPosedDexParser implements DexParser {
|
||||
ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
long cookie;
|
||||
StringId[] strings;
|
||||
TypeId[] typeIds;
|
||||
ProtoId[] protoIds;
|
||||
FieldId[] fieldIds;
|
||||
MethodId[] methodIds;
|
||||
ClassDef[] classDefs;
|
||||
|
||||
public LSPosedDexParser(ByteBuffer buffer) throws IOException {
|
||||
lock.writeLock().lock();
|
||||
if (!buffer.isDirect() || !buffer.asReadOnlyBuffer().hasArray()) {
|
||||
var newBuffer = ByteBuffer.allocateDirect(buffer.capacity());
|
||||
newBuffer.put(buffer);
|
||||
buffer = newBuffer;
|
||||
}
|
||||
try {
|
||||
var out = (Object[]) DexParserBridge.parseDex(buffer);
|
||||
// out[0]: Long
|
||||
// out[1]: String[]
|
||||
// out[2]: int[][]
|
||||
// out[3]: int[][3]
|
||||
// out[4]: int[][3]
|
||||
// out[5]: int[][3]
|
||||
// out[6]: int[][]
|
||||
// out[7]: Object[][][][]
|
||||
cookie = (Long) out[0];
|
||||
var strings = (Object[]) out[1];
|
||||
this.strings = new StringId[strings.length];
|
||||
for (int i = 0; i < strings.length; ++i) {
|
||||
this.strings[i] = new LSPosedStringId(i, strings[i]);
|
||||
}
|
||||
|
||||
var typeIds = (int[]) out[2];
|
||||
this.typeIds = new TypeId[typeIds.length];
|
||||
for (int i = 0; i < typeIds.length; ++i) {
|
||||
this.typeIds[i] = new LSPosedTypeId(i, typeIds[i]);
|
||||
}
|
||||
|
||||
var protoIds = (int[][]) out[3];
|
||||
this.protoIds = new ProtoId[protoIds.length];
|
||||
for (int i = 0; i < protoIds.length; ++i) {
|
||||
this.protoIds[i] = new LSPosedProtoId(i, protoIds[i]);
|
||||
}
|
||||
|
||||
var fieldIds = (int[][]) out[4];
|
||||
this.fieldIds = new FieldId[fieldIds.length];
|
||||
for (int i = 0; i < fieldIds.length; ++i) {
|
||||
this.fieldIds[i] = new LSPosedFieldId(i, fieldIds[i]);
|
||||
}
|
||||
|
||||
var methodIds = (int[][]) out[5];
|
||||
this.methodIds = new MethodId[methodIds.length];
|
||||
for (int i = 0; i < methodIds.length; ++i) {
|
||||
this.methodIds[i] = new LSPosedMethodId(i, methodIds[i]);
|
||||
}
|
||||
|
||||
var classDefs = (int[][]) out[6];
|
||||
this.classDefs = new ClassDef[classDefs.length];
|
||||
var annotations = (Object[][][][]) out[7];
|
||||
for (int i = 0; i < classDefs.length; ++i) {
|
||||
this.classDefs[i] = new LSPosedClassDef(classDefs[i], annotations[i]);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
close();
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
close();
|
||||
throw new IOException("Invalid dex file", e);
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
static class LSPosedId implements Id {
|
||||
final int id;
|
||||
|
||||
LSPosedId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
static class LSPosedStringId extends LSPosedId implements StringId {
|
||||
@NonNull
|
||||
final String string;
|
||||
|
||||
LSPosedStringId(int id, @NonNull Object string) {
|
||||
super(id);
|
||||
this.string = (String) string;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String getString() {
|
||||
return string;
|
||||
}
|
||||
}
|
||||
|
||||
class LSPosedTypeId extends LSPosedId implements TypeId {
|
||||
@NonNull
|
||||
final StringId descriptor;
|
||||
|
||||
LSPosedTypeId(int id, int descriptor) {
|
||||
super(id);
|
||||
this.descriptor = strings[descriptor];
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public StringId getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
class LSPosedProtoId extends LSPosedId implements ProtoId {
|
||||
@NonNull
|
||||
final StringId shorty;
|
||||
@NonNull
|
||||
final TypeId returnType;
|
||||
@Nullable
|
||||
final TypeId[] parameters;
|
||||
|
||||
LSPosedProtoId(int id, @NonNull int[] protoId) {
|
||||
super(id);
|
||||
this.shorty = strings[protoId[0]];
|
||||
this.returnType = typeIds[protoId[1]];
|
||||
if (protoId.length > 2) {
|
||||
this.parameters = new TypeId[protoId.length - 2];
|
||||
for (int i = 2; i < parameters.length; ++i) {
|
||||
this.parameters[i] = typeIds[protoId[i]];
|
||||
}
|
||||
} else {
|
||||
this.parameters = null;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public StringId getShorty() {
|
||||
return shorty;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public TypeId getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TypeId[] getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
|
||||
class LSPosedFieldId extends LSPosedId implements FieldId {
|
||||
@NonNull
|
||||
final TypeId type;
|
||||
@NonNull
|
||||
final TypeId declaringClass;
|
||||
@NonNull
|
||||
final StringId name;
|
||||
|
||||
LSPosedFieldId(int id, @NonNull int[] fieldId) {
|
||||
super(id);
|
||||
this.type = typeIds[fieldId[0]];
|
||||
this.declaringClass = typeIds[fieldId[1]];
|
||||
this.name = strings[fieldId[2]];
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public TypeId getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public TypeId getDeclaringClass() {
|
||||
return declaringClass;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public StringId getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
class LSPosedMethodId extends LSPosedId implements MethodId {
|
||||
@NonNull
|
||||
final TypeId declaringClass;
|
||||
@NonNull
|
||||
final ProtoId prototype;
|
||||
@NonNull
|
||||
final StringId name;
|
||||
|
||||
LSPosedMethodId(int id, @NonNull int[] methodId) {
|
||||
super(id);
|
||||
declaringClass = typeIds[methodId[0]];
|
||||
prototype = protoIds[methodId[1]];
|
||||
name = strings[methodId[2]];
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public TypeId getDeclaringClass() {
|
||||
return declaringClass;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ProtoId getPrototype() {
|
||||
return prototype;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public StringId getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
class LSPosedEncodedField implements EncodedField {
|
||||
@NonNull
|
||||
final FieldId field;
|
||||
final int accessFlags;
|
||||
|
||||
LSPosedEncodedField(int field, int accessFlags) {
|
||||
this.field = fieldIds[field];
|
||||
this.accessFlags = accessFlags;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public FieldId getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAccessFlags() {
|
||||
return accessFlags;
|
||||
}
|
||||
}
|
||||
|
||||
class LSPosedEncodedMethod implements EncodedMethod {
|
||||
@NonNull
|
||||
final MethodId method;
|
||||
final int accessFlags;
|
||||
final int code;
|
||||
MethodId[] invokedMethods = null;
|
||||
FieldId[] accessedFields = null;
|
||||
FieldId[] assignedFields = null;
|
||||
StringId[] referredStrings = null;
|
||||
int[] opcodes = null;
|
||||
|
||||
LSPosedEncodedMethod(int method, int accessFlags, int code) {
|
||||
this.method = methodIds[method];
|
||||
this.accessFlags = accessFlags;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
synchronized void parseMethod() {
|
||||
if (invokedMethods != null) return;
|
||||
lock.readLock().lock();
|
||||
try {
|
||||
if (cookie == 0) throw new IllegalStateException("DexParser is closed");
|
||||
var out = (Object[]) DexParserBridge.parseMethod(cookie, code);
|
||||
var invokedMethods = (int[]) out[0];
|
||||
this.invokedMethods = new MethodId[invokedMethods.length];
|
||||
for (int i = 0; i < invokedMethods.length; ++i) {
|
||||
this.invokedMethods[i] = methodIds[invokedMethods[i]];
|
||||
}
|
||||
var accessedFields = (int[]) out[1];
|
||||
this.accessedFields = new FieldId[accessedFields.length];
|
||||
for (int i = 0; i < accessedFields.length; ++i) {
|
||||
this.accessedFields[i] = fieldIds[accessedFields[i]];
|
||||
}
|
||||
var assignedFields = (int[]) out[2];
|
||||
this.assignedFields = new FieldId[assignedFields.length];
|
||||
for (int i = 0; i < assignedFields.length; ++i) {
|
||||
this.assignedFields[i] = fieldIds[assignedFields[i]];
|
||||
}
|
||||
var referredStrings = (int[]) out[3];
|
||||
this.referredStrings = new StringId[referredStrings.length];
|
||||
for (int i = 0; i < referredStrings.length; ++i) {
|
||||
this.referredStrings[i] = strings[referredStrings[i]];
|
||||
}
|
||||
opcodes = (int[]) out[4];
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MethodId getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAccessFlags() {
|
||||
return accessFlags;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MethodId[] getInvokedMethods() {
|
||||
if (invokedMethods == null) {
|
||||
parseMethod();
|
||||
}
|
||||
return invokedMethods;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public FieldId[] getAccessedFields() {
|
||||
if (accessedFields == null) {
|
||||
parseMethod();
|
||||
}
|
||||
return accessedFields;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public FieldId[] getAssignedFields() {
|
||||
if (assignedFields == null) {
|
||||
parseMethod();
|
||||
}
|
||||
return assignedFields;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public int[] getOpcodes() {
|
||||
if (opcodes == null) {
|
||||
parseMethod();
|
||||
}
|
||||
return opcodes;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public StringId[] getReferredString() {
|
||||
if (referredStrings == null) {
|
||||
parseMethod();
|
||||
}
|
||||
return referredStrings;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class LSPosedAnnotation implements Annotation {
|
||||
int visibility;
|
||||
@NonNull
|
||||
final TypeId type;
|
||||
@Nullable
|
||||
final AnnotationElement[] elements;
|
||||
|
||||
LSPosedAnnotation(int visibility, int type, @NonNull Object[] elements) {
|
||||
this.visibility = visibility;
|
||||
this.type = typeIds[type];
|
||||
var a = (int[]) elements[0];
|
||||
var b = (ByteBuffer[]) elements[1];
|
||||
this.elements = new AnnotationElement[b.length];
|
||||
for (int i = 0; i < b.length; ++i) {
|
||||
this.elements[i] = new LSPosedAnnotationElement(a[i * 2], a[i * 2 + 1], b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVisibility() {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public TypeId getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public AnnotationElement[] getElements() {
|
||||
return elements;
|
||||
}
|
||||
}
|
||||
|
||||
class LSPosedAnnotationElement implements AnnotationElement {
|
||||
@NonNull
|
||||
final StringId name;
|
||||
final int valueType;
|
||||
@Nullable
|
||||
final byte[] value;
|
||||
|
||||
LSPosedAnnotationElement(int name, int valueType, @Nullable ByteBuffer value) {
|
||||
this.name = strings[name];
|
||||
this.valueType = valueType;
|
||||
if (value != null) {
|
||||
this.value = value.array();
|
||||
} else {
|
||||
this.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public StringId getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getValueType() {
|
||||
return valueType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public byte[] getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
class LSPosedFieldAnnotation implements FieldAnnotation {
|
||||
@NonNull
|
||||
FieldId field;
|
||||
@NonNull
|
||||
Annotation[] annotations;
|
||||
|
||||
LSPosedFieldAnnotation(int field, @NonNull Object[] annotations) {
|
||||
this.field = fieldIds[field];
|
||||
var a = (int[]) annotations[0];
|
||||
var b = (Object[][]) annotations[1];
|
||||
this.annotations = new Annotation[b.length];
|
||||
for (int i = 0; i < b.length; ++i) {
|
||||
this.annotations[i] = new LSPosedAnnotation(a[2 * i], a[2 * i + 1], b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public FieldId getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Annotation[] getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
}
|
||||
|
||||
class LSPosedMethodAnnotation implements MethodAnnotation {
|
||||
@NonNull
|
||||
MethodId method;
|
||||
@NonNull
|
||||
Annotation[] annotations;
|
||||
|
||||
LSPosedMethodAnnotation(int method, @NonNull Object[] annotations) {
|
||||
this.method = methodIds[method];
|
||||
var a = (int[]) annotations[0];
|
||||
var b = (Object[][]) annotations[1];
|
||||
this.annotations = new Annotation[b.length];
|
||||
for (int i = 0; i < b.length; ++i) {
|
||||
this.annotations[i] = new LSPosedAnnotation(a[2 * i], a[2 * i + 1], b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MethodId getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Annotation[] getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
}
|
||||
|
||||
class LSPosedParameterAnnotation implements ParameterAnnotation {
|
||||
@NonNull
|
||||
MethodId method;
|
||||
@NonNull
|
||||
Annotation[][] annotations;
|
||||
|
||||
LSPosedParameterAnnotation(int method, @NonNull Object[][] annotations) {
|
||||
this.method = methodIds[method];
|
||||
this.annotations = new Annotation[annotations.length][];
|
||||
for (int i = 0; i < annotations.length; ++i) {
|
||||
var a = (int[]) annotations[i][0];
|
||||
var b = (Object[][]) annotations[i][1];
|
||||
this.annotations[i] = new Annotation[b.length];
|
||||
for (int j = 0; j < b.length; ++j) {
|
||||
this.annotations[i][j] = new LSPosedAnnotation(a[2 * j], a[2 * j + 1], b[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MethodId getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Annotation[][] getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
}
|
||||
|
||||
class LSPosedClassDef implements ClassDef {
|
||||
@NonNull
|
||||
final TypeId type;
|
||||
final int accessFlags;
|
||||
@Nullable
|
||||
final TypeId superClass;
|
||||
@Nullable
|
||||
final TypeId[] interfaces;
|
||||
@Nullable
|
||||
final StringId sourceFile;
|
||||
@NonNull
|
||||
final EncodedField[] staticFields;
|
||||
@NonNull
|
||||
final EncodedField[] instanceFields;
|
||||
@NonNull
|
||||
final EncodedMethod[] directMethods;
|
||||
@NonNull
|
||||
final EncodedMethod[] virtualMethods;
|
||||
|
||||
@NonNull
|
||||
final FieldAnnotation[] fieldAnnotations;
|
||||
@NonNull
|
||||
final MethodAnnotation[] methodAnnotations;
|
||||
@NonNull
|
||||
final ParameterAnnotation[] parameterAnnotations;
|
||||
|
||||
LSPosedClassDef(int[] classDef, Object[][][] annotation) {
|
||||
// annotation[0]: int[]
|
||||
// annotation[1]: int[]
|
||||
var iter = 0;
|
||||
type = typeIds[classDef[iter++]];
|
||||
accessFlags = classDef[iter++];
|
||||
var superClass = classDef[iter++];
|
||||
this.superClass = superClass == NO_INDEX ? null : typeIds[superClass];
|
||||
var sourceFile = classDef[iter++];
|
||||
this.sourceFile = sourceFile == NO_INDEX ? null : strings[sourceFile];
|
||||
var num_interfaces = classDef[iter++];
|
||||
interfaces = new TypeId[num_interfaces];
|
||||
for (int i = 0; i < num_interfaces; ++i) {
|
||||
interfaces[i] = typeIds[classDef[iter++]];
|
||||
}
|
||||
var num_static_fields = classDef[iter++];
|
||||
staticFields = new EncodedField[num_static_fields];
|
||||
for (int i = 0; i < num_static_fields; ++i) {
|
||||
var field = classDef[iter++];
|
||||
var accessFlags = classDef[iter++];
|
||||
staticFields[i] = new LSPosedEncodedField(field, accessFlags);
|
||||
}
|
||||
var num_instance_fields = classDef[iter++];
|
||||
instanceFields = new EncodedField[num_instance_fields];
|
||||
for (int i = 0; i < num_instance_fields; ++i) {
|
||||
var field = classDef[iter++];
|
||||
var accessFlags = classDef[iter++];
|
||||
instanceFields[i] = new LSPosedEncodedField(field, accessFlags);
|
||||
}
|
||||
var num_direct_methods = classDef[iter++];
|
||||
directMethods = new EncodedMethod[num_direct_methods];
|
||||
for (int i = 0; i < num_direct_methods; ++i) {
|
||||
var method = classDef[iter++];
|
||||
var accessFlags = classDef[iter++];
|
||||
var code = classDef[iter++];
|
||||
directMethods[i] = new LSPosedEncodedMethod(method, accessFlags, code);
|
||||
}
|
||||
var num_virtual_methods = classDef[iter++];
|
||||
virtualMethods = new EncodedMethod[num_virtual_methods];
|
||||
for (int i = 0; i < num_virtual_methods; ++i) {
|
||||
var method = classDef[iter++];
|
||||
var accessFlags = classDef[iter++];
|
||||
var code = classDef[iter++];
|
||||
virtualMethods[i] = new LSPosedEncodedMethod(method, accessFlags, code);
|
||||
}
|
||||
|
||||
var num_field_annotations = classDef[iter++];
|
||||
fieldAnnotations = new FieldAnnotation[num_field_annotations];
|
||||
for (int i = 0; i < num_field_annotations; ++i) {
|
||||
var field = classDef[iter++];
|
||||
fieldAnnotations[i] = new LSPosedFieldAnnotation(field, annotation[0][i]);
|
||||
}
|
||||
|
||||
var num_method_annotations = classDef[iter++];
|
||||
methodAnnotations = new MethodAnnotation[num_method_annotations];
|
||||
for (int i = 0; i < num_method_annotations; ++i) {
|
||||
var method = classDef[iter++];
|
||||
methodAnnotations[i] = new LSPosedMethodAnnotation(method, annotation[1][i]);
|
||||
}
|
||||
|
||||
var num_parameter_annotations = classDef[iter++];
|
||||
parameterAnnotations = new ParameterAnnotation[num_parameter_annotations];
|
||||
for (int i = 0; i < num_parameter_annotations; ++i) {
|
||||
var method = classDef[iter++];
|
||||
parameterAnnotations[i] = new LSPosedParameterAnnotation(method, (Object[][]) annotation[2][i]);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public TypeId getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAccessFlags() {
|
||||
return accessFlags;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TypeId getSuperClass() {
|
||||
return superClass;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TypeId[] getInterfaces() {
|
||||
return interfaces;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public StringId getSourceFile() {
|
||||
return sourceFile;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public EncodedField[] getStaticFields() {
|
||||
return staticFields;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public EncodedField[] getInstanceFields() {
|
||||
return instanceFields;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public EncodedMethod[] getDirectMethods() {
|
||||
return directMethods;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public EncodedMethod[] getVirtualMethods() {
|
||||
return virtualMethods;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public FieldAnnotation[] getFieldAnnotations() {
|
||||
return fieldAnnotations;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public MethodAnnotation[] getMethodAnnotations() {
|
||||
return methodAnnotations;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ParameterAnnotation[] getParameterAnnotations() {
|
||||
return parameterAnnotations;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ClassDef[] getClassDef() {
|
||||
return classDefs;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public StringId[] getStringId() {
|
||||
return strings;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public TypeId[] getTypeId() {
|
||||
return typeIds;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public FieldId[] getFieldId() {
|
||||
return fieldIds;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public MethodId[] getMethodId() {
|
||||
return methodIds;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ProtoId[] getProtoId() {
|
||||
return protoIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
if (cookie == 0) return;
|
||||
DexParserBridge.closeDex(cookie);
|
||||
cookie = 0L;
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package org.lsposed.lspd.nativebridge;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class DexParserBridge {
|
||||
public static native Object parseDex(ByteBuffer byteBuffer) throws IOException;
|
||||
|
||||
public static native Object parseMethod(long cookie, int code);
|
||||
|
||||
public static native void closeDex(long cookie);
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import androidx.annotation.Nullable;
|
|||
import java.nio.ByteBuffer;
|
||||
|
||||
public interface DexParser extends AutoCloseable {
|
||||
int NO_INDEX = 0xffffffff;
|
||||
|
||||
interface ClassDef {
|
||||
@NonNull
|
||||
|
|
@ -17,7 +18,7 @@ public interface DexParser extends AutoCloseable {
|
|||
TypeId getSuperClass();
|
||||
|
||||
@Nullable
|
||||
TypeList getInterfaces();
|
||||
TypeId[] getInterfaces();
|
||||
|
||||
@Nullable
|
||||
StringId getSourceFile();
|
||||
|
|
@ -49,7 +50,7 @@ public interface DexParser extends AutoCloseable {
|
|||
FieldId getField();
|
||||
|
||||
@NonNull
|
||||
AnnotationItem[] getAnnotations();
|
||||
Annotation[] getAnnotations();
|
||||
}
|
||||
|
||||
interface MethodAnnotation {
|
||||
|
|
@ -57,7 +58,7 @@ public interface DexParser extends AutoCloseable {
|
|||
MethodId getMethod();
|
||||
|
||||
@NonNull
|
||||
AnnotationItem[] getAnnotations();
|
||||
Annotation[] getAnnotations();
|
||||
}
|
||||
|
||||
interface ParameterAnnotation {
|
||||
|
|
@ -65,22 +66,12 @@ public interface DexParser extends AutoCloseable {
|
|||
MethodId getMethod();
|
||||
|
||||
@NonNull
|
||||
AnnotationList getAnnotations();
|
||||
}
|
||||
|
||||
interface AnnotationList {
|
||||
@NonNull
|
||||
AnnotationItem[] getAnnotations();
|
||||
}
|
||||
|
||||
interface AnnotationItem {
|
||||
int getVisibility();
|
||||
|
||||
@NonNull
|
||||
Annotation getAnnotation();
|
||||
Annotation[][] getAnnotations();
|
||||
}
|
||||
|
||||
interface Annotation {
|
||||
int getVisibility();
|
||||
|
||||
@NonNull
|
||||
TypeId getType();
|
||||
|
||||
|
|
@ -89,14 +80,14 @@ public interface DexParser extends AutoCloseable {
|
|||
}
|
||||
|
||||
interface AnnotationElement {
|
||||
int getType();
|
||||
|
||||
ByteBuffer value();
|
||||
}
|
||||
|
||||
interface TypeList {
|
||||
@NonNull
|
||||
TypeId[] getTypes();
|
||||
StringId getName();
|
||||
|
||||
@NonNull
|
||||
int getValueType();
|
||||
|
||||
@Nullable
|
||||
byte[] getValue();
|
||||
}
|
||||
|
||||
interface TypeId {
|
||||
|
|
@ -130,11 +121,11 @@ public interface DexParser extends AutoCloseable {
|
|||
int[] getOpcodes();
|
||||
|
||||
@NonNull
|
||||
StringId getReferencedString();
|
||||
StringId[] getReferredString();
|
||||
}
|
||||
|
||||
interface Id {
|
||||
int getIndex();
|
||||
int getId();
|
||||
}
|
||||
|
||||
interface StringId extends Id {
|
||||
|
|
@ -158,7 +149,7 @@ public interface DexParser extends AutoCloseable {
|
|||
TypeId getDeclaringClass();
|
||||
|
||||
@NonNull
|
||||
ProtoId getProtoType();
|
||||
ProtoId getPrototype();
|
||||
|
||||
@NonNull
|
||||
StringId getName();
|
||||
|
|
@ -170,6 +161,9 @@ public interface DexParser extends AutoCloseable {
|
|||
|
||||
@NonNull
|
||||
TypeId getReturnType();
|
||||
|
||||
@Nullable
|
||||
TypeId[] getParameters();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
|
@ -189,7 +183,4 @@ public interface DexParser extends AutoCloseable {
|
|||
|
||||
@NonNull
|
||||
ProtoId[] getProtoId();
|
||||
|
||||
@NonNull
|
||||
TypeList[] getTypeList();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue