Skip to content

Commit

Permalink
break android p
Browse files Browse the repository at this point in the history
  • Loading branch information
yuwei.wang committed Feb 26, 2019
1 parent aa53b40 commit bd4a7c5
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 46 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,11 @@ At present, UETool provides functionality as follows:

```gradle
dependencies {
debugCompile 'me.ele:uetool:1.0.15'
releaseCompile 'me.ele:uetool-no-op:1.0.15'
debugCompile 'me.ele:uetool:1.0.16'
releaseCompile 'me.ele:uetool-no-op:1.0.16'
// if you want to show more attrs about Fresco's DraweeView
debugCompile 'me.ele:uetool-fresco:1.0.15'
debugCompile 'me.ele:uetool-fresco:1.0.16'
}
```

Expand Down
6 changes: 3 additions & 3 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ UETool 是一个各方人员(设计师、程序员、测试)都可以使用

```gradle
dependencies {
debugCompile 'me.ele:uetool:1.0.15'
releaseCompile 'me.ele:uetool-no-op:1.0.15'
debugCompile 'me.ele:uetool:1.0.16'
releaseCompile 'me.ele:uetool-no-op:1.0.16'
// if you want to show more attrs about Fresco's DraweeView
debugCompile 'me.ele:uetool-fresco:1.0.15'
debugCompile 'me.ele:uetool-fresco:1.0.16'
}
```

Expand Down
8 changes: 4 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

buildscript {
ext.versions = ['minSdk' : 14,
'targetSdk' : 26,
'compileSdk' : 26,
'buildTool' : '26.0.1',
'targetSdk' : 28,
'compileSdk' : 28,
'buildTool' : '28.0.1',

'supportLibrary': '27.1.1',
'fresco' : '1.4.0',

'release' : '1.0.15',]
'release' : '1.0.16',]
repositories {
jcenter()
}
Expand Down
89 changes: 89 additions & 0 deletions uetool-base/src/main/java/me/ele/uetool/base/ReflectionP.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package me.ele.uetool.base;

import android.annotation.TargetApi;
import android.os.Build;
import android.util.Log;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
* 来自 52 破解
* https://www.52pojie.cn/thread-877958-1-1.html
*/
public class ReflectionP {

/**
* 用Unsafe清除classloader
* 该方法仅对同一个类生效,所以必须在需要的类中添加使用,不可以跨类调用
*
* @param cls 需要清除Loader的类
*/
@SuppressWarnings({"unchecked", "JavaReflectionMemberAccess"})
@TargetApi(Build.VERSION_CODES.P)
private static void clearClassLoaderInClass(Class cls) {
try {
//Unsafe类
Class unsafeClass = Class.forName("sun.misc.Unsafe");
//取Unsafe实例字段
Field unsafeInstanceField = unsafeClass.getDeclaredField("theUnsafe");
//放开Unsafe实例字段权限
unsafeInstanceField.setAccessible(true);
//取Unsafe实例
Object unsafeInstance = unsafeInstanceField.get(null);
//取objectFieldOffset方法取偏移量
Method objectFieldOffset = unsafeClass.getMethod("objectFieldOffset", Field.class);
//Class的classLoader字段
Field classLoaderField = Class.class.getDeclaredField("classLoader");
//使classLoader可见
classLoaderField.setAccessible(true);
//取putObject方法进行置空
Method putObject = unsafeClass.getMethod("putObject", Object.class, long.class, Object.class);
//值为8,这里不用硬编码,看什么时候等到classLoader字段被404了再用
long offset = (long) objectFieldOffset.invoke(unsafeInstance, classLoaderField);

Log.i("@", "clearClassLoaderInClass: classLoader offset=" + offset);
//偏移量为8处置空
putObject.invoke(unsafeInstance, cls, offset, null);
} catch (Throwable throwable) {
Log.e("@", "clearClassLoaderInClass: ", throwable);
}
}

/**
* 恢复classloader:清除loader可能会造成问题
* (java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace
* available)
* 反射完成后恢复loader
*
* @param cls 需要恢复Loader的类
*/
@TargetApi(Build.VERSION_CODES.P)
private static void restoreLoaderInClass(Class cls) {
try {
Field classLoaderField = Class.class.getDeclaredField("classLoader");
classLoaderField.setAccessible(true);
//If this object represents a primitive type or void, null is returned.
if (cls != null && !cls.isPrimitive() && classLoaderField.get(cls) == null) {
Log.w("@", "restoreLoaderInClass: classloader is null!");
classLoaderField.set(cls, Thread.currentThread().getContextClassLoader());
}
} catch (Exception e) {
Log.e("@", "restoreLoaderInClass: ", e);
}
}

public static void breakAndroidP(Func0 func0) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
clearClassLoaderInClass(func0.getClass());
func0.call();
restoreLoaderInClass(func0.getClass());
} else {
func0.call();
}
}

public interface Func0 {
void call();
}
}
73 changes: 37 additions & 36 deletions uetool/src/main/java/me/ele/uetool/CollectViewsLayout.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.*;
import android.os.Build;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
Expand All @@ -15,20 +11,16 @@
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Toast;
import me.ele.uetool.base.DimenUtil;
import me.ele.uetool.base.Element;
import me.ele.uetool.base.ReflectionP;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import me.ele.uetool.base.DimenUtil;
import me.ele.uetool.base.Element;

import static me.ele.uetool.base.DimenUtil.dip2px;
import static me.ele.uetool.base.DimenUtil.getScreenHeight;
import static me.ele.uetool.base.DimenUtil.getScreenWidth;
import static me.ele.uetool.base.DimenUtil.px2dip;
import static me.ele.uetool.base.DimenUtil.sp2px;
import static me.ele.uetool.base.DimenUtil.*;

public class CollectViewsLayout extends View {

Expand Down Expand Up @@ -82,20 +74,20 @@ public CollectViewsLayout(Context context, @Nullable AttributeSet attrs, int def
protected void onAttachedToWindow() {
super.onAttachedToWindow();
try {
Activity targetActivity = UETool.getInstance().getTargetActivity();
WindowManager windowManager = targetActivity.getWindowManager();
final Activity targetActivity = UETool.getInstance().getTargetActivity();
final WindowManager windowManager = targetActivity.getWindowManager();

if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
Field mGlobalField = Class.forName("android.view.WindowManagerImpl").getDeclaredField("mGlobal");
final Field mGlobalField = Class.forName("android.view.WindowManagerImpl").getDeclaredField("mGlobal");
mGlobalField.setAccessible(true);

if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
Field mViewsField = Class.forName("android.view.WindowManagerGlobal").getDeclaredField("mViews");
mViewsField.setAccessible(true);
List<View> views;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
views = (List<View>) mViewsField.get(mGlobalField.get(windowManager));
}else {
} else {
views = Arrays.asList((View[]) mViewsField.get(mGlobalField.get(windowManager)));
}

Expand All @@ -107,25 +99,34 @@ protected void onAttachedToWindow() {
}
}
} else {
Field mRootsField = Class.forName("android.view.WindowManagerGlobal").getDeclaredField("mRoots");
mRootsField.setAccessible(true);
List viewRootImpls;
viewRootImpls = (List) mRootsField.get(mGlobalField.get(windowManager));
for (int i = viewRootImpls.size() - 1; i >= 0; i--) {
Class clazz = Class.forName("android.view.ViewRootImpl");
Object object = viewRootImpls.get(i);
Field mWindowAttributesField = clazz.getDeclaredField("mWindowAttributes");
mWindowAttributesField.setAccessible(true);
Field mViewField = clazz.getDeclaredField("mView");
mViewField.setAccessible(true);
View decorView = (View) mViewField.get(object);
WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) mWindowAttributesField.get(object);
if (layoutParams.getTitle().toString().contains(targetActivity.getClass().getName())
|| getTargetDecorView(targetActivity, decorView) != null) {
traverse(decorView);
break;
ReflectionP.breakAndroidP(new ReflectionP.Func0() {
@Override
public void call() {
try {
Field mRootsField = Class.forName("android.view.WindowManagerGlobal").getDeclaredField("mRoots");
mRootsField.setAccessible(true);
List viewRootImpls;
viewRootImpls = (List) mRootsField.get(mGlobalField.get(windowManager));
for (int i = viewRootImpls.size() - 1; i >= 0; i--) {
Class clazz = Class.forName("android.view.ViewRootImpl");
Object object = viewRootImpls.get(i);
Field mWindowAttributesField = clazz.getDeclaredField("mWindowAttributes");
mWindowAttributesField.setAccessible(true);
Field mViewField = clazz.getDeclaredField("mView");
mViewField.setAccessible(true);
View decorView = (View) mViewField.get(object);
WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) mWindowAttributesField.get(object);
if (layoutParams.getTitle().toString().contains(targetActivity.getClass().getName())
|| getTargetDecorView(targetActivity, decorView) != null) {
traverse(decorView);
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
} else {
// http://androidxref.com/4.1.1/xref/frameworks/base/core/java/android/view/WindowManagerImpl.java
Expand Down

0 comments on commit bd4a7c5

Please sign in to comment.