我更新了Nexus5X到安卓N,现在当我在上面安装应用程序(调试或发布)时,我在每个屏幕过渡中都会得到TransactionTooLargeException。这款应用程序在所有其他设备上都能正常工作。在PlayStore上运行的代码基本相同的旧应用程序在Nexus5X上也可以运行。有没有人有同样的问题?
java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 592196 bytes
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3752)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
Caused by: android.os.TransactionTooLargeException: data parcel size 592196 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:615)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3606)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3744)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 发布于 2017-04-21 09:46:50
作为Android N,改变行为并抛出TransactionTooLargeException,而不是记录错误。
try {
if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + activity);
ActivityManagerNative.getDefault().activityStopped(
activity.token, state, persistentState, description);
} catch (RemoteException ex) {
if (ex instanceof TransactionTooLargeException
&& activity.packageInfo.getTargetSdkVersion() < Build.VERSION_CODES.N) {
Log.e(TAG, "App sent too much data in instance state, so it was ignored", ex);
return;
}
throw ex.rethrowFromSystemServer();
}我的解决方案是挂钩ActivityMangerProxy实例并尝试捕获activityStopped方法。
代码如下:
private boolean hookActivityManagerNative() {
try {
ClassLoader loader = ClassLoader.getSystemClassLoader();
Field singletonField = ReflectUtils.findField(loader.loadClass("android.app.ActivityManagerNative"), "gDefault");
ReflectUtils.ReflectObject singletonObjWrap = ReflectUtils.wrap(singletonField.get(null));
Object realActivityManager = singletonObjWrap.getChildField("mInstance").get();
Object fakeActivityManager = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{loader.loadClass("android.app.IActivityManager")}, new ActivityManagerHook(realActivityManager));
singletonObjWrap.setChildField("mInstance", fakeActivityManager);
return true;
} catch (Throwable e) {
AppHolder.getThirdPartUtils().markException(e);
return false;
}
}
private static class ActivityManagerHook implements InvocationHandler {
private Object origin;
ActivityManagerHook(Object origin) {
this.origin = origin;
}
public Object getOrigin() {
return origin;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
switch (method.getName()) {
//ActivityManagerNative.getDefault().activityStopped(activity.token, state, persistentState, description);
case "activityStopped": {
try {
return method.invoke(getOrigin(), args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
return method.invoke(getOrigin(), args);
}
}而反射辅助类是
public class ReflectUtils {
private static final HashMap<String, Field> fieldCache = new HashMap<>();
private static final HashMap<String, Method> methodCache = new HashMap<>();
public static Field findField(Class<?> clazz, String fieldName) throws Throwable {
String fullFieldName = clazz.getName() + '#' + fieldName;
if (fieldCache.containsKey(fullFieldName)) {
Field field = fieldCache.get(fullFieldName);
if (field == null)
throw new NoSuchFieldError(fullFieldName);
return field;
}
try {
Field field = findFieldRecursiveImpl(clazz, fieldName);
field.setAccessible(true);
fieldCache.put(fullFieldName, field);
return field;
} catch (NoSuchFieldException e) {
fieldCache.put(fullFieldName, null);
throw new NoSuchFieldError(fullFieldName);
}
}
private static Field findFieldRecursiveImpl(Class<?> clazz, String fieldName) throws NoSuchFieldException {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
while (true) {
clazz = clazz.getSuperclass();
if (clazz == null || clazz.equals(Object.class))
break;
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException ignored) {
}
}
throw e;
}
}
public static Method findMethodExact(Class<?> clazz, String methodName, Class<?>... parameterTypes) throws Throwable {
String fullMethodName = clazz.getName() + '#' + methodName + getParametersString(parameterTypes) + "#exact";
if (methodCache.containsKey(fullMethodName)) {
Method method = methodCache.get(fullMethodName);
if (method == null)
throw new NoSuchMethodError(fullMethodName);
return method;
}
try {
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
method.setAccessible(true);
methodCache.put(fullMethodName, method);
return method;
} catch (NoSuchMethodException e) {
methodCache.put(fullMethodName, null);
throw new NoSuchMethodError(fullMethodName);
}
}
/**
* Returns an array of the given classes.
*/
public static Class<?>[] getClassesAsArray(Class<?>... clazzes) {
return clazzes;
}
private static String getParametersString(Class<?>... clazzes) {
StringBuilder sb = new StringBuilder("(");
boolean first = true;
for (Class<?> clazz : clazzes) {
if (first)
first = false;
else
sb.append(",");
if (clazz != null)
sb.append(clazz.getCanonicalName());
else
sb.append("null");
}
sb.append(")");
return sb.toString();
}
/**
* Retrieve classes from an array, where each element might either be a Class
* already, or a String with the full class name.
*/
private static Class<?>[] getParameterClasses(ClassLoader classLoader, Object[] parameterTypes) throws ClassNotFoundException {
Class<?>[] parameterClasses = null;
for (int i = parameterTypes.length - 1; i >= 0; i--) {
Object type = parameterTypes[i];
if (type == null)
throw new ClassNotFoundException("parameter type must not be null", null);
if (parameterClasses == null)
parameterClasses = new Class<?>[i + 1];
if (type instanceof Class)
parameterClasses[i] = (Class<?>) type;
else if (type instanceof String)
parameterClasses[i] = findClass((String) type, classLoader);
else
throw new ClassNotFoundException("parameter type must either be specified as Class or String", null);
}
// if there are no arguments for the method
if (parameterClasses == null)
parameterClasses = new Class<?>[0];
return parameterClasses;
}
public static Class<?> findClass(String className, ClassLoader classLoader) throws ClassNotFoundException {
if (classLoader == null)
classLoader = ClassLoader.getSystemClassLoader();
return classLoader.loadClass(className);
}
public static ReflectObject wrap(Object object) {
return new ReflectObject(object);
}
public static class ReflectObject {
private Object object;
private ReflectObject(Object o) {
this.object = o;
}
public ReflectObject getChildField(String fieldName) throws Throwable {
Object child = ReflectUtils.findField(object.getClass(), fieldName).get(object);
return ReflectUtils.wrap(child);
}
public void setChildField(String fieldName, Object o) throws Throwable {
ReflectUtils.findField(object.getClass(), fieldName).set(object, o);
}
public ReflectObject callMethod(String methodName, Object... args) throws Throwable {
Class<?>[] clazzs = new Class[args.length];
for (int i = 0; i < args.length; i++) {
clazzs[i] = args.getClass();
}
Method method = ReflectUtils.findMethodExact(object.getClass(), methodName, clazzs);
return ReflectUtils.wrap(method.invoke(object, args));
}
public <T> T getAs(Class<T> clazz) {
return (T) object;
}
public <T> T get() {
return (T) object;
}
}
}https://stackoverflow.com/questions/39098590
复制相似问题