Add commons-lang as a subproject
Avoid using a local version of this apache module
This commit is contained in:
parent
5a64b8c139
commit
6b2ce6c614
|
|
@ -19,3 +19,6 @@
|
||||||
[submodule "external/xz-embedded"]
|
[submodule "external/xz-embedded"]
|
||||||
path = external/xz-embedded
|
path = external/xz-embedded
|
||||||
url = https://github.com/tukaani-project/xz-embedded
|
url = https://github.com/tukaani-project/xz-embedded
|
||||||
|
[submodule "apache/commons-lang"]
|
||||||
|
path = apache/commons-lang
|
||||||
|
url = https://github.com/apache/commons-lang
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
val androidSourceCompatibility: JavaVersion by rootProject.extra
|
||||||
|
val androidTargetCompatibility: JavaVersion by rootProject.extra
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id("java-library")
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = androidSourceCompatibility
|
||||||
|
targetCompatibility = androidTargetCompatibility
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
java.srcDirs("commons-lang/src/main/java", "local")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit c2cd0525d97495daa820d2fcb29d6875b52c09a6
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.commons.lang3.local.reflect;
|
package org.apache.commons.lang3.reflect;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
@ -57,7 +57,7 @@ copy {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(libs.libxposed.api)
|
api(libs.libxposed.api)
|
||||||
implementation(libs.commons.lang3)
|
implementation(projects.apache)
|
||||||
implementation(projects.axml)
|
implementation(projects.axml)
|
||||||
implementation(projects.hiddenapi.bridge)
|
implementation(projects.hiddenapi.bridge)
|
||||||
implementation(projects.services.daemonService)
|
implementation(projects.services.daemonService)
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@ import android.content.res.Resources;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.apache.commons.lang3.local.ClassUtils;
|
import org.apache.commons.lang3.ClassUtils;
|
||||||
import org.apache.commons.lang3.local.reflect.MemberUtilsX;
|
import org.apache.commons.lang3.reflect.MemberUtilsX;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
|
|
||||||
|
|
@ -1,154 +0,0 @@
|
||||||
package org.apache.commons.lang3.local;
|
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
|
||||||
|
|
||||||
public class ArrayUtils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An empty immutable {@link Class} array.
|
|
||||||
*/
|
|
||||||
public static final Class<?>[] EMPTY_CLASS_ARRAY = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defensive programming technique to change a {@code null}
|
|
||||||
* reference to an empty one.
|
|
||||||
* <p>
|
|
||||||
* This method returns an empty array for a {@code null} input array.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* As a memory optimizing technique an empty array passed in will be overridden with
|
|
||||||
* the empty {@code public static} references in this class.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param array the array to check for {@code null} or empty
|
|
||||||
* @return the same array, {@code public static} empty array if {@code null} or empty input
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
public static Class<?>[] nullToEmpty(final Class<?>[] array) {
|
|
||||||
return nullTo(array, EMPTY_CLASS_ARRAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defensive programming technique to change a {@code null}
|
|
||||||
* reference to an empty one.
|
|
||||||
* <p>
|
|
||||||
* This method returns a default array for a {@code null} input array.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* As a memory optimizing technique an empty array passed in will be overridden with
|
|
||||||
* the empty {@code public static} references in this class.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param <T> The array type.
|
|
||||||
* @param array the array to check for {@code null} or empty
|
|
||||||
* @param defaultArray A default array, usually empty.
|
|
||||||
* @return the same array, or defaultArray if {@code null} or empty input.
|
|
||||||
* @since 3.15.0
|
|
||||||
*/
|
|
||||||
public static <T> T[] nullTo(final T[] array, final T[] defaultArray) {
|
|
||||||
return isEmpty(array) ? defaultArray : array;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if an array of Objects is empty or {@code null}.
|
|
||||||
*
|
|
||||||
* @param array the array to test
|
|
||||||
* @return {@code true} if the array is empty or {@code null}
|
|
||||||
* @since 2.1
|
|
||||||
*/
|
|
||||||
public static boolean isEmpty(final Object[] array) {
|
|
||||||
return isArrayEmpty(array);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if an array is empty or {@code null}.
|
|
||||||
*
|
|
||||||
* @param array the array to test
|
|
||||||
* @return {@code true} if the array is empty or {@code null}
|
|
||||||
*/
|
|
||||||
private static boolean isArrayEmpty(final Object array) {
|
|
||||||
return getLength(array) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the length of the specified array.
|
|
||||||
* This method can deal with {@link Object} arrays and with primitive arrays.
|
|
||||||
* <p>
|
|
||||||
* If the input array is {@code null}, {@code 0} is returned.
|
|
||||||
* </p>
|
|
||||||
* <pre>
|
|
||||||
* ArrayUtils.getLength(null) = 0
|
|
||||||
* ArrayUtils.getLength([]) = 0
|
|
||||||
* ArrayUtils.getLength([null]) = 1
|
|
||||||
* ArrayUtils.getLength([true, false]) = 2
|
|
||||||
* ArrayUtils.getLength([1, 2, 3]) = 3
|
|
||||||
* ArrayUtils.getLength(["a", "b", "c"]) = 3
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param array the array to retrieve the length from, may be null
|
|
||||||
* @return The length of the array, or {@code 0} if the array is {@code null}
|
|
||||||
* @throws IllegalArgumentException if the object argument is not an array.
|
|
||||||
* @since 2.1
|
|
||||||
*/
|
|
||||||
public static int getLength(final Object array) {
|
|
||||||
return array != null ? Array.getLength(array) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether two arrays are the same length, treating
|
|
||||||
* {@code null} arrays as length {@code 0}.
|
|
||||||
* <p>
|
|
||||||
* Any multi-dimensional aspects of the arrays are ignored.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param array1 the first array, may be {@code null}
|
|
||||||
* @param array2 the second array, may be {@code null}
|
|
||||||
* @return {@code true} if length of arrays matches, treating
|
|
||||||
* {@code null} as an empty array
|
|
||||||
* @since 3.11
|
|
||||||
*/
|
|
||||||
public static boolean isSameLength(final Object array1, final Object array2) {
|
|
||||||
return getLength(array1) == getLength(array2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Outputs an array as a String, treating {@code null} as an empty array.
|
|
||||||
* <p>
|
|
||||||
* Multi-dimensional arrays are handled correctly, including
|
|
||||||
* multi-dimensional primitive arrays.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* The format is that of Java source code, for example {@code {a,b}}.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param array the array to get a toString for, may be {@code null}
|
|
||||||
* @return a String representation of the array, '{}' if null array input
|
|
||||||
*/
|
|
||||||
public static String toString(final Object array) {
|
|
||||||
return toString(array, "{}");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Outputs an array as a String handling {@code null}s.
|
|
||||||
* <p>
|
|
||||||
* Multi-dimensional arrays are handled correctly, including
|
|
||||||
* multi-dimensional primitive arrays.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* The format is that of Java source code, for example {@code {a,b}}.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param array the array to get a toString for, may be {@code null}
|
|
||||||
* @param stringIfNull the String to return if the array is {@code null}
|
|
||||||
* @return a String representation of the array
|
|
||||||
*/
|
|
||||||
public static String toString(final Object array, final String stringIfNull) {
|
|
||||||
if (array == null) {
|
|
||||||
return stringIfNull;
|
|
||||||
}
|
|
||||||
// return new ToStringBuilder(array, ToStringStyle.SIMPLE_STYLE).append(array).toString();
|
|
||||||
// TODO: add a proper implement
|
|
||||||
return array.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,73 +0,0 @@
|
||||||
package org.apache.commons.lang3.local;
|
|
||||||
|
|
||||||
public class StringUtils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A String for a space character.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static final String SPACE = " ";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The empty String {@code ""}.
|
|
||||||
*/
|
|
||||||
public static final String EMPTY = "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes all whitespaces from a String as defined by
|
|
||||||
* {@link Character#isWhitespace(char)}.
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* StringUtils.deleteWhitespace(null) = null
|
|
||||||
* StringUtils.deleteWhitespace("") = ""
|
|
||||||
* StringUtils.deleteWhitespace("abc") = "abc"
|
|
||||||
* StringUtils.deleteWhitespace(" ab c ") = "abc"
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param str the String to delete whitespace from, may be null
|
|
||||||
* @return the String without whitespaces, {@code null} if null String input
|
|
||||||
*/
|
|
||||||
public static String deleteWhitespace(final String str) {
|
|
||||||
if (isEmpty(str)) {
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
final int sz = str.length();
|
|
||||||
final char[] chs = new char[sz];
|
|
||||||
int count = 0;
|
|
||||||
for (int i = 0; i < sz; i++) {
|
|
||||||
if (!Character.isWhitespace(str.charAt(i))) {
|
|
||||||
chs[count++] = str.charAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count == sz) {
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
if (count == 0) {
|
|
||||||
return EMPTY;
|
|
||||||
}
|
|
||||||
return new String(chs, 0, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a CharSequence is empty ("") or null.
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* StringUtils.isEmpty(null) = true
|
|
||||||
* StringUtils.isEmpty("") = true
|
|
||||||
* StringUtils.isEmpty(" ") = false
|
|
||||||
* StringUtils.isEmpty("bob") = false
|
|
||||||
* StringUtils.isEmpty(" bob ") = false
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* <p>NOTE: This method changed in Lang version 2.0.
|
|
||||||
* It no longer trims the CharSequence.
|
|
||||||
* That functionality is available in isBlank().</p>
|
|
||||||
*
|
|
||||||
* @param cs the CharSequence to check, may be null
|
|
||||||
* @return {@code true} if the CharSequence is empty or null
|
|
||||||
* @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence)
|
|
||||||
*/
|
|
||||||
public static boolean isEmpty(final CharSequence cs) {
|
|
||||||
return cs == null || cs.length() == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.commons.lang3.local.mutable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides mutable access to a value.
|
|
||||||
* <p>
|
|
||||||
* {@link Mutable} is used as a generic interface to the implementations in this package.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* A typical use case would be to enable a primitive or string to be passed to a method and allow that method to
|
|
||||||
* effectively change the value of the primitive/string. Another use case is to store a frequently changing primitive in
|
|
||||||
* a collection (for example a total in a map) without needing to create new Integer/Long wrapper objects.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param <T> the type to set and get
|
|
||||||
* @since 2.1
|
|
||||||
*/
|
|
||||||
public interface Mutable<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value of this mutable.
|
|
||||||
*
|
|
||||||
* @return the stored value
|
|
||||||
*/
|
|
||||||
T getValue();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the value of this mutable.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
* the value to store
|
|
||||||
* @throws NullPointerException
|
|
||||||
* if the object is null and null is invalid
|
|
||||||
* @throws ClassCastException
|
|
||||||
* if the type is invalid
|
|
||||||
*/
|
|
||||||
void setValue(T value);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,121 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.commons.lang3.local.mutable;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A mutable {@link Object} wrapper.
|
|
||||||
*
|
|
||||||
* @param <T> the type to set and get
|
|
||||||
* @since 2.1
|
|
||||||
*/
|
|
||||||
public class MutableObject<T> implements Mutable<T>, Serializable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Required for serialization support.
|
|
||||||
*
|
|
||||||
* @see java.io.Serializable
|
|
||||||
*/
|
|
||||||
private static final long serialVersionUID = 86241875189L;
|
|
||||||
|
|
||||||
/** The mutable value. */
|
|
||||||
private T value;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new MutableObject with the default value of {@code null}.
|
|
||||||
*/
|
|
||||||
public MutableObject() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new MutableObject with the specified value.
|
|
||||||
*
|
|
||||||
* @param value the initial value to store
|
|
||||||
*/
|
|
||||||
public MutableObject(final T value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares this object against the specified object. The result is {@code true} if and only if the argument
|
|
||||||
* is not {@code null} and is a {@link MutableObject} object that contains the same {@link T}
|
|
||||||
* value as this object.
|
|
||||||
*
|
|
||||||
* @param obj the object to compare with, {@code null} returns {@code false}
|
|
||||||
* @return {@code true} if the objects are the same;
|
|
||||||
* {@code true} if the objects have equivalent {@code value} fields;
|
|
||||||
* {@code false} otherwise.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean equals(final Object obj) {
|
|
||||||
if (obj == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (this.getClass() == obj.getClass()) {
|
|
||||||
final MutableObject<?> that = (MutableObject<?>) obj;
|
|
||||||
return Objects.equals(this.value, that.value);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value.
|
|
||||||
*
|
|
||||||
* @return the value, may be null
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public T getValue() {
|
|
||||||
return this.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value's hash code or {@code 0} if the value is {@code null}.
|
|
||||||
*
|
|
||||||
* @return the value's hash code or {@code 0} if the value is {@code null}.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hashCode(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the value.
|
|
||||||
*
|
|
||||||
* @param value the value to set
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void setValue(final T value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the String value of this mutable.
|
|
||||||
*
|
|
||||||
* @return the mutable value as a string
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return Objects.toString(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,342 +0,0 @@
|
||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.apache.commons.lang3.local.reflect;
|
|
||||||
|
|
||||||
import java.lang.reflect.AccessibleObject;
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.Member;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.local.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contains common code for working with {@link java.lang.reflect.Method Methods}/{@link java.lang.reflect.Constructor Constructors},
|
|
||||||
* extracted and refactored from {@link MethodUtils} when it was imported from Commons BeanUtils.
|
|
||||||
*
|
|
||||||
* @since 2.5
|
|
||||||
*/
|
|
||||||
final class MemberUtils {
|
|
||||||
// TODO extract an interface to implement compareParameterSets(...)?
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class providing a subset of the API of java.lang.reflect.Executable in Java 1.8,
|
|
||||||
* providing a common representation for function signatures for Constructors and Methods.
|
|
||||||
*/
|
|
||||||
private static final class Executable {
|
|
||||||
private static Executable of(final Constructor<?> constructor) {
|
|
||||||
return new Executable(constructor);
|
|
||||||
}
|
|
||||||
private static Executable of(final Method method) {
|
|
||||||
return new Executable(method);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Class<?>[] parameterTypes;
|
|
||||||
|
|
||||||
private final boolean isVarArgs;
|
|
||||||
|
|
||||||
private Executable(final Constructor<?> constructor) {
|
|
||||||
parameterTypes = constructor.getParameterTypes();
|
|
||||||
isVarArgs = constructor.isVarArgs();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Executable(final Method method) {
|
|
||||||
parameterTypes = method.getParameterTypes();
|
|
||||||
isVarArgs = method.isVarArgs();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<?>[] getParameterTypes() {
|
|
||||||
return parameterTypes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isVarArgs() {
|
|
||||||
return isVarArgs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int ACCESS_TEST = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
|
|
||||||
|
|
||||||
/** Array of primitive number types ordered by "promotability" */
|
|
||||||
private static final Class<?>[] ORDERED_PRIMITIVE_TYPES = { Byte.TYPE, Short.TYPE,
|
|
||||||
Character.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares the relative fitness of two Constructors in terms of how well they
|
|
||||||
* match a set of runtime parameter types, such that a list ordered
|
|
||||||
* by the results of the comparison would return the best match first
|
|
||||||
* (least).
|
|
||||||
*
|
|
||||||
* @param left the "left" Constructor
|
|
||||||
* @param right the "right" Constructor
|
|
||||||
* @param actual the runtime parameter types to match against
|
|
||||||
* {@code left}/{@code right}
|
|
||||||
* @return int consistent with {@code compare} semantics
|
|
||||||
* @since 3.5
|
|
||||||
*/
|
|
||||||
static int compareConstructorFit(final Constructor<?> left, final Constructor<?> right, final Class<?>[] actual) {
|
|
||||||
return compareParameterTypes(Executable.of(left), Executable.of(right), actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares the relative fitness of two Methods in terms of how well they
|
|
||||||
* match a set of runtime parameter types, such that a list ordered
|
|
||||||
* by the results of the comparison would return the best match first
|
|
||||||
* (least).
|
|
||||||
*
|
|
||||||
* @param left the "left" Method
|
|
||||||
* @param right the "right" Method
|
|
||||||
* @param actual the runtime parameter types to match against
|
|
||||||
* {@code left}/{@code right}
|
|
||||||
* @return int consistent with {@code compare} semantics
|
|
||||||
* @since 3.5
|
|
||||||
*/
|
|
||||||
static int compareMethodFit(final Method left, final Method right, final Class<?>[] actual) {
|
|
||||||
return compareParameterTypes(Executable.of(left), Executable.of(right), actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares the relative fitness of two Executables in terms of how well they
|
|
||||||
* match a set of runtime parameter types, such that a list ordered
|
|
||||||
* by the results of the comparison would return the best match first
|
|
||||||
* (least).
|
|
||||||
*
|
|
||||||
* @param left the "left" Executable
|
|
||||||
* @param right the "right" Executable
|
|
||||||
* @param actual the runtime parameter types to match against
|
|
||||||
* {@code left}/{@code right}
|
|
||||||
* @return int consistent with {@code compare} semantics
|
|
||||||
*/
|
|
||||||
private static int compareParameterTypes(final Executable left, final Executable right, final Class<?>[] actual) {
|
|
||||||
final float leftCost = getTotalTransformationCost(actual, left);
|
|
||||||
final float rightCost = getTotalTransformationCost(actual, right);
|
|
||||||
return Float.compare(leftCost, rightCost);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the number of steps needed to turn the source class into
|
|
||||||
* the destination class. This represents the number of steps in the object
|
|
||||||
* hierarchy graph.
|
|
||||||
* @param srcClass The source class
|
|
||||||
* @param destClass The destination class
|
|
||||||
* @return The cost of transforming an object
|
|
||||||
*/
|
|
||||||
private static float getObjectTransformationCost(Class<?> srcClass, final Class<?> destClass) {
|
|
||||||
if (destClass.isPrimitive()) {
|
|
||||||
return getPrimitivePromotionCost(srcClass, destClass);
|
|
||||||
}
|
|
||||||
float cost = 0.0f;
|
|
||||||
while (srcClass != null && !destClass.equals(srcClass)) {
|
|
||||||
if (destClass.isInterface() && ClassUtils.isAssignable(srcClass, destClass)) {
|
|
||||||
// slight penalty for interface match.
|
|
||||||
// we still want an exact match to override an interface match,
|
|
||||||
// but
|
|
||||||
// an interface match should override anything where we have to
|
|
||||||
// get a superclass.
|
|
||||||
cost += 0.25f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cost++;
|
|
||||||
srcClass = srcClass.getSuperclass();
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* If the destination class is null, we've traveled all the way up to
|
|
||||||
* an Object match. We'll penalize this by adding 1.5 to the cost.
|
|
||||||
*/
|
|
||||||
if (srcClass == null) {
|
|
||||||
cost += 1.5f;
|
|
||||||
}
|
|
||||||
return cost;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the number of steps required to promote a primitive number to another
|
|
||||||
* type.
|
|
||||||
* @param srcClass the (primitive) source class
|
|
||||||
* @param destClass the (primitive) destination class
|
|
||||||
* @return The cost of promoting the primitive
|
|
||||||
*/
|
|
||||||
private static float getPrimitivePromotionCost(final Class<?> srcClass, final Class<?> destClass) {
|
|
||||||
if (srcClass == null) {
|
|
||||||
return 1.5f;
|
|
||||||
}
|
|
||||||
float cost = 0.0f;
|
|
||||||
Class<?> cls = srcClass;
|
|
||||||
if (!cls.isPrimitive()) {
|
|
||||||
// slight unwrapping penalty
|
|
||||||
cost += 0.1f;
|
|
||||||
cls = ClassUtils.wrapperToPrimitive(cls);
|
|
||||||
}
|
|
||||||
for (int i = 0; cls != destClass && i < ORDERED_PRIMITIVE_TYPES.length; i++) {
|
|
||||||
if (cls == ORDERED_PRIMITIVE_TYPES[i]) {
|
|
||||||
cost += 0.1f;
|
|
||||||
if (i < ORDERED_PRIMITIVE_TYPES.length - 1) {
|
|
||||||
cls = ORDERED_PRIMITIVE_TYPES[i + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cost;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the sum of the object transformation cost for each class in the
|
|
||||||
* source argument list.
|
|
||||||
* @param srcArgs The source arguments
|
|
||||||
* @param executable The executable to calculate transformation costs for
|
|
||||||
* @return The total transformation cost
|
|
||||||
*/
|
|
||||||
private static float getTotalTransformationCost(final Class<?>[] srcArgs, final Executable executable) {
|
|
||||||
final Class<?>[] destArgs = executable.getParameterTypes();
|
|
||||||
final boolean isVarArgs = executable.isVarArgs();
|
|
||||||
|
|
||||||
// "source" and "destination" are the actual and declared args respectively.
|
|
||||||
float totalCost = 0.0f;
|
|
||||||
final long normalArgsLen = isVarArgs ? destArgs.length - 1 : destArgs.length;
|
|
||||||
if (srcArgs.length < normalArgsLen) {
|
|
||||||
return Float.MAX_VALUE;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < normalArgsLen; i++) {
|
|
||||||
totalCost += getObjectTransformationCost(srcArgs[i], destArgs[i]);
|
|
||||||
}
|
|
||||||
if (isVarArgs) {
|
|
||||||
// When isVarArgs is true, srcArgs and dstArgs may differ in length.
|
|
||||||
// There are two special cases to consider:
|
|
||||||
final boolean noVarArgsPassed = srcArgs.length < destArgs.length;
|
|
||||||
final boolean explicitArrayForVarargs = srcArgs.length == destArgs.length && srcArgs[srcArgs.length - 1] != null
|
|
||||||
&& srcArgs[srcArgs.length - 1].isArray();
|
|
||||||
|
|
||||||
final float varArgsCost = 0.001f;
|
|
||||||
final Class<?> destClass = destArgs[destArgs.length - 1].getComponentType();
|
|
||||||
if (noVarArgsPassed) {
|
|
||||||
// When no varargs passed, the best match is the most generic matching type, not the most specific.
|
|
||||||
totalCost += getObjectTransformationCost(destClass, Object.class) + varArgsCost;
|
|
||||||
} else if (explicitArrayForVarargs) {
|
|
||||||
final Class<?> sourceClass = srcArgs[srcArgs.length - 1].getComponentType();
|
|
||||||
totalCost += getObjectTransformationCost(sourceClass, destClass) + varArgsCost;
|
|
||||||
} else {
|
|
||||||
// This is typical varargs case.
|
|
||||||
for (int i = destArgs.length - 1; i < srcArgs.length; i++) {
|
|
||||||
final Class<?> srcClass = srcArgs[i];
|
|
||||||
totalCost += getObjectTransformationCost(srcClass, destClass) + varArgsCost;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return totalCost;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests whether a {@link Member} is accessible.
|
|
||||||
*
|
|
||||||
* @param member Member to test, may be null.
|
|
||||||
* @return {@code true} if {@code m} is accessible
|
|
||||||
*/
|
|
||||||
static boolean isAccessible(final Member member) {
|
|
||||||
return isPublic(member) && !member.isSynthetic();
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean isMatchingConstructor(final Constructor<?> method, final Class<?>[] parameterTypes) {
|
|
||||||
return isMatchingExecutable(Executable.of(method), parameterTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isMatchingExecutable(final Executable method, final Class<?>[] parameterTypes) {
|
|
||||||
final Class<?>[] methodParameterTypes = method.getParameterTypes();
|
|
||||||
if (ClassUtils.isAssignable(parameterTypes, methodParameterTypes, true)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (method.isVarArgs()) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < methodParameterTypes.length - 1 && i < parameterTypes.length; i++) {
|
|
||||||
if (!ClassUtils.isAssignable(parameterTypes[i], methodParameterTypes[i], true)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
final Class<?> varArgParameterType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType();
|
|
||||||
for (; i < parameterTypes.length; i++) {
|
|
||||||
if (!ClassUtils.isAssignable(parameterTypes[i], varArgParameterType, true)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static boolean isMatchingMethod(final Method method, final Class<?>[] parameterTypes) {
|
|
||||||
return isMatchingExecutable(Executable.of(method), parameterTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests whether a given set of modifiers implies package access.
|
|
||||||
*
|
|
||||||
* @param modifiers to test
|
|
||||||
* @return {@code true} unless {@code package}/{@code protected}/{@code private} modifier detected
|
|
||||||
*/
|
|
||||||
static boolean isPackageAccess(final int modifiers) {
|
|
||||||
return (modifiers & ACCESS_TEST) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests whether a {@link Member} is public.
|
|
||||||
*
|
|
||||||
* @param member Member to test, may be null.
|
|
||||||
* @return {@code true} if {@code m} is public
|
|
||||||
*/
|
|
||||||
static boolean isPublic(final Member member) {
|
|
||||||
return member != null && Modifier.isPublic(member.getModifiers());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests whether a {@link Member} is static.
|
|
||||||
*
|
|
||||||
* @param member Member to test, may be null.
|
|
||||||
* @return {@code true} if {@code m} is static
|
|
||||||
*/
|
|
||||||
static boolean isStatic(final Member member) {
|
|
||||||
return member != null && Modifier.isStatic(member.getModifiers());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default access superclass workaround.
|
|
||||||
* <p>
|
|
||||||
* When a {@code public} class has a default access superclass with {@code public} members,
|
|
||||||
* these members are accessible. Calling them from compiled code works fine.
|
|
||||||
* Unfortunately, on some JVMs, using reflection to invoke these members
|
|
||||||
* seems to (wrongly) prevent access even when the modifier is {@code public}.
|
|
||||||
* Calling {@code setAccessible(true)} solves the problem but will only work from
|
|
||||||
* sufficiently privileged code. Better workarounds would be gratefully
|
|
||||||
* accepted.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param obj the AccessibleObject to set as accessible, may be null.
|
|
||||||
* @return a boolean indicating whether the accessibility of the object was set to true.
|
|
||||||
*/
|
|
||||||
static <T extends AccessibleObject> T setAccessibleWorkaround(final T obj) {
|
|
||||||
if (obj == null || obj.isAccessible()) {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
final Member m = (Member) obj;
|
|
||||||
if (!obj.isAccessible() && isPublic(m) && isPackageAccess(m.getDeclaringClass().getModifiers())) {
|
|
||||||
try {
|
|
||||||
obj.setAccessible(true);
|
|
||||||
return obj;
|
|
||||||
} catch (final SecurityException ignored) {
|
|
||||||
// ignore in favor of subsequent IllegalAccessException
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -116,7 +116,7 @@ android.applicationVariants.all {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(libs.libxposed.`interface`)
|
implementation(libs.libxposed.`interface`)
|
||||||
implementation(libs.agp.apksig)
|
implementation(libs.agp.apksig)
|
||||||
implementation(libs.commons.lang3)
|
implementation(projects.apache)
|
||||||
implementation(projects.hiddenapi.bridge)
|
implementation(projects.hiddenapi.bridge)
|
||||||
implementation(projects.services.daemonService)
|
implementation(projects.services.daemonService)
|
||||||
implementation(projects.services.managerService)
|
implementation(projects.services.managerService)
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@ okhttp-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-i
|
||||||
|
|
||||||
agp-apksig = { group = "com.android.tools.build", name = "apksig", version.ref = "agp" }
|
agp-apksig = { group = "com.android.tools.build", name = "apksig", version.ref = "agp" }
|
||||||
appiconloader = { module = "me.zhanghai.android.appiconloader:appiconloader", version = "1.5.0" }
|
appiconloader = { module = "me.zhanghai.android.appiconloader:appiconloader", version = "1.5.0" }
|
||||||
commons-lang3 = { module = "org.apache.commons:commons-lang3", version = "3.17.0" }
|
|
||||||
material = { module = "com.google.android.material:material", version = "1.12.0" }
|
material = { module = "com.google.android.material:material", version = "1.12.0" }
|
||||||
gson = { module = "com.google.code.gson:gson", version = "2.11.0" }
|
gson = { module = "com.google.code.gson:gson", version = "2.11.0" }
|
||||||
hiddenapibypass = { module = "org.lsposed.hiddenapibypass:hiddenapibypass", version = "4.3" }
|
hiddenapibypass = { module = "org.lsposed.hiddenapibypass:hiddenapibypass", version = "4.3" }
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ dependencyResolutionManagement {
|
||||||
|
|
||||||
rootProject.name = "LSPosed"
|
rootProject.name = "LSPosed"
|
||||||
include(
|
include(
|
||||||
|
":apache",
|
||||||
":app",
|
":app",
|
||||||
":axml",
|
":axml",
|
||||||
":core",
|
":core",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue