From 90293240cc622bb58cb1de741f86cbc0889c03e8 Mon Sep 17 00:00:00 2001 From: act262 Date: Mon, 28 Oct 2019 11:18:53 +0800 Subject: [PATCH] Fix meizu 16th NPE Fill AppInfo to avoid NullPointerException on some devices. Fixes Signed-off-by: Romain Vimont --- .../com/genymobile/scrcpy/ScreenEncoder.java | 1 + .../com/genymobile/scrcpy/Workarounds.java | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java b/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java index 504e9540..c9a37f84 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java +++ b/server/src/main/java/com/genymobile/scrcpy/ScreenEncoder.java @@ -53,6 +53,7 @@ public class ScreenEncoder implements Device.RotationListener { public void streamScreen(Device device, FileDescriptor fd) throws IOException { Workarounds.prepareMainLooper(); + Workarounds.fillAppInfo(); MediaFormat format = createFormat(bitRate, maxFps, iFrameInterval); device.setRotationListener(this); diff --git a/server/src/main/java/com/genymobile/scrcpy/Workarounds.java b/server/src/main/java/com/genymobile/scrcpy/Workarounds.java index 4dbf152e..f45d82a4 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Workarounds.java +++ b/server/src/main/java/com/genymobile/scrcpy/Workarounds.java @@ -1,7 +1,12 @@ 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 @@ -18,4 +23,42 @@ public final class Workarounds { // 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()); + } + } }