Compare commits

...

2 Commits

Author SHA1 Message Date
act262
d61c2ab3f9 Fix meizu 16th NPE
Fill AppInfo to avoid NullPointerException on some devices.

Fixes <https://github.com/Genymobile/scrcpy/issues/365>

Signed-off-by: Romain Vimont <rom@rom1v.com>
2019-11-13 12:32:20 +01:00
Romain Vimont
e6cca8db5c Move workarounds to a separate class
Extract workarounds (currently only one) to a separate class to avoid
polluting the main code.
2019-11-13 12:08:36 +01:00
2 changed files with 66 additions and 10 deletions

View File

@ -7,7 +7,6 @@ import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.os.IBinder;
import android.os.Looper;
import android.view.Surface;
import java.io.FileDescriptor;
@ -55,15 +54,8 @@ public class ScreenEncoder implements Device.RotationListener {
}
public void streamScreen(Device device, FileDescriptor fd) throws IOException {
// Some devices internally create a Handler when creating an input Surface, causing an exception:
// "Can't create handler inside thread that has not called Looper.prepare()"
// <https://github.com/Genymobile/scrcpy/issues/240>
//
// Use Looper.prepareMainLooper() instead of Looper.prepare() to avoid a NullPointerException:
// "Attempt to read from field 'android.os.MessageQueue android.os.Looper.mQueue'
// on a null object reference"
// <https://github.com/Genymobile/scrcpy/issues/921>
Looper.prepareMainLooper();
Workarounds.prepareMainLooper();
Workarounds.fillAppInfo();
MediaFormat format = createFormat(bitRate, frameRate, iFrameInterval);
device.setRotationListener(this);

View File

@ -0,0 +1,64 @@
package com.genymobile.scrcpy;
import android.annotation.SuppressLint;
import android.content.pm.ApplicationInfo;
import android.os.Looper;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public final class Workarounds {
private Workarounds() {
// not instantiable
}
public static void prepareMainLooper() {
// Some devices internally create a Handler when creating an input Surface, causing an exception:
// "Can't create handler inside thread that has not called Looper.prepare()"
// <https://github.com/Genymobile/scrcpy/issues/240>
//
// Use Looper.prepareMainLooper() instead of Looper.prepare() to avoid a NullPointerException:
// "Attempt to read from field 'android.os.MessageQueue android.os.Looper.mQueue'
// on a null object reference"
// <https://github.com/Genymobile/scrcpy/issues/921>
Looper.prepareMainLooper();
}
@SuppressLint("PrivateApi")
public static void fillAppInfo() {
try {
// ActivityThread activityThread = new ActivityThread();
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Constructor<?> activityThreadConstructor = activityThreadClass.getDeclaredConstructor();
activityThreadConstructor.setAccessible(true);
Object activityThread = activityThreadConstructor.newInstance();
// ActivityThread.sCurrentActivityThread = activityThread;
Field sCurrentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");
sCurrentActivityThreadField.setAccessible(true);
sCurrentActivityThreadField.set(null, activityThread);
// ActivityThread.AppBindData appBindData = new ActivityThread.AppBindData();
Class<?> appBindDataClass = Class.forName("android.app.ActivityThread$AppBindData");
Constructor<?> appBindDataConstructor = appBindDataClass.getDeclaredConstructor();
appBindDataConstructor.setAccessible(true);
Object appBindData = appBindDataConstructor.newInstance();
ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.packageName = "com.genymobile.scrcpy";
// appBindData.appInfo = applicationInfo;
Field appInfo = appBindDataClass.getDeclaredField("appInfo");
appInfo.setAccessible(true);
appInfo.set(appBindData, applicationInfo);
// activityThread.mBoundApplication = appBindData;
Field mBoundApplicationField = activityThreadClass.getDeclaredField("mBoundApplication");
mBoundApplicationField.setAccessible(true);
mBoundApplicationField.set(activityThread, appBindData);
} catch (Throwable throwable) {
// this is a workaround, so failing is not an error
Ln.w("Could not fill app info: " + throwable.getMessage());
}
}
}