package kz.virtex.htc.tweaker.mods;
import android.content.pm.ApplicationInfo;
import android.os.SystemClock;
import android.util.EventLog;
import android.util.Slog;
import com.android.server.am.EventLogTags;
import de.robv.android.xposed.XC_MethodReplacement;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.XC_MethodHook.MethodHookParam;
public class Bugs
{
public static void tweak_fix98918()
{
// --------------------------------------------------
// https://android-review.googlesource.com/#/c/98918/
// --------------------------------------------------
try {
final Class<?> TaskRecord = XposedHelpers.findClass("com.android.server.am.TaskRecord", null);
XposedHelpers.findAndHookMethod(TaskRecord, "setFrontOfTask", new XC_MethodReplacement()
{
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable
{
Object mActivities = XposedHelpers.getObjectField(param.thisObject, "mActivities");
boolean foundFront = false;
final int numActivities = (Integer) XposedHelpers.callMethod(mActivities, "size");
for (int activityNdx = 0; activityNdx < numActivities; activityNdx++) {
final Object r = XposedHelpers.callMethod(mActivities, "get", activityNdx);
if (foundFront || XposedHelpers.getBooleanField(r, "finishing")) {
XposedHelpers.setBooleanField(r, "frontOfTask", false);
} else {
XposedHelpers.setBooleanField(r, "frontOfTask", true);
foundFront = true;
}
}
if (!foundFront && numActivities > 0) {
Object get = XposedHelpers.callMethod(mActivities, "get", 0);
XposedHelpers.setBooleanField(get, "frontOfTask", true);
}
return null;
}
});
} catch (Throwable t) {
//XposedBridge.log(t);
}
}
public static void tweak_fix81970()
{
try {
final Class<?> ActiveServices = XposedHelpers.findClass("com.android.server.am.ActiveServices", null);
XposedHelpers.findAndHookMethod(ActiveServices, "killServicesLocked", "com.android.server.am.ProcessRecord", "boolean", new XC_MethodReplacement()
{
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable
{
// XposedBridge.log("killServicesLocked happen");
Boolean DEBUG_SERVICE = (Boolean) XposedHelpers.getStaticBooleanField(ActiveServices, "DEBUG_SERVICE");
String TAG = (String) XposedHelpers.getStaticObjectField(ActiveServices, "TAG");
Object app = param.args[0];
boolean allowRestart = (Boolean) param.args[1];
Object services = XposedHelpers.getObjectField(app, "services");
int size = (Integer) XposedHelpers.callMethod(services, "size");
// First clear app state from services.
for (int i = size - 1; i >= 0; i--) {
Object sr = XposedHelpers.callMethod(services, "valueAt", i);
Object stats = XposedHelpers.getObjectField(sr, "stats");
synchronized (XposedHelpers.callMethod(stats, "getBatteryStats")) {
XposedHelpers.callMethod(stats, "stopLaunchedLocked");
}
Object sr_app = XposedHelpers.getObjectField(sr, "app");
Boolean persistent = XposedHelpers.getBooleanField(sr_app, "persistent");
Boolean stopIfKilled = XposedHelpers.getBooleanField(sr, "stopIfKilled");
if (sr_app != null && !persistent && stopIfKilled) {
Object sr_app_services = XposedHelpers.getObjectField(sr_app, "services");
XposedHelpers.callMethod(sr_app_services, "remove", sr);
}
XposedHelpers.setObjectField(sr, "app", null);
XposedHelpers.setObjectField(sr, "isolatedProc", null);
XposedHelpers.setObjectField(sr, "executeNesting", 0);
XposedHelpers.callMethod(sr, "forceClearTracker");
Object mDestroyingServices = XposedHelpers.getObjectField(param.thisObject, "mDestroyingServices");
Boolean check = (Boolean) XposedHelpers.callMethod(mDestroyingServices, "remove", sr);
if (check) {
if (DEBUG_SERVICE)
Slog.v(TAG, "killServices remove destroying " + sr);
}
Object bindings = XposedHelpers.getObjectField(sr, "bindings");
final int numClients = (Integer) XposedHelpers.callMethod(bindings, "size");
for (int bindingi = numClients - 1; bindingi >= 0; bindingi--) {
Object IntentBindRecord = XposedHelpers.callMethod(bindings, "valueAt", bindingi);
if (DEBUG_SERVICE)
Slog.v(TAG, "Killing binding " + IntentBindRecord + ": shouldUnbind=" + XposedHelpers.getObjectField(IntentBindRecord, "hasBound"));
XposedHelpers.setObjectField(IntentBindRecord, "binder", null);
XposedHelpers.setObjectField(IntentBindRecord, "requested", false);
XposedHelpers.setObjectField(IntentBindRecord, "received", false);
XposedHelpers.setObjectField(IntentBindRecord, "hasBound", false);
}
}
// Clean up any connections this application has to
// other
// services.
Object connections = XposedHelpers.getObjectField(app, "connections");
size = (Integer) XposedHelpers.callMethod(connections, "size");
for (int i = size - 1; i >= 0; i--) {
Object ConnectionRecord = XposedHelpers.callMethod(connections, "valueAt", i);
XposedHelpers.callMethod(param.thisObject, "removeConnectionLocked", ConnectionRecord, app, null);
}
XposedHelpers.callMethod(connections, "clear");
Object smap = XposedHelpers.callMethod(param.thisObject, "getServiceMap", XposedHelpers.getObjectField(app, "userId"));
// Now do remaining service cleanup.
services = XposedHelpers.getObjectField(app, "services");
size = (Integer) XposedHelpers.callMethod(services, "size");
for (int i = size - 1; i >= 0; i--) {
Object sr = XposedHelpers.callMethod(services, "valueAt", i);
Object mServicesByName = XposedHelpers.getObjectField(smap, "mServicesByName");
if (XposedHelpers.callMethod(mServicesByName, "get", XposedHelpers.getObjectField(sr, "name")) != sr) {
Object cur = XposedHelpers.callMethod(mServicesByName, "get", XposedHelpers.getObjectField(sr, "name"));
Slog.wtf(TAG, "Service " + sr + " in process " + app + " not same as in map: " + cur);
Object app_services = XposedHelpers.getObjectField(app, "services");
XposedHelpers.callMethod(app_services, "removeAt", i);
continue;
}
// Any services running in the application may
// need to be
// placed back in the pending list.
Object serviceInfo = XposedHelpers.getObjectField(sr, "serviceInfo");
Object applicationInfo = XposedHelpers.getObjectField(serviceInfo, "applicationInfo");
if (allowRestart && XposedHelpers.getIntField(sr, "crashCount") >= 2 && (XposedHelpers.getIntField(applicationInfo, "flags") & ApplicationInfo.FLAG_PERSISTENT) == 0) {
Slog.w(TAG, "Service crashed " + XposedHelpers.getIntField(sr, "crashCount") + " times, stopping: " + sr);
EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH, XposedHelpers.getObjectField(sr, "userId"), XposedHelpers.getObjectField(sr, "crashCount"), XposedHelpers.getObjectField(sr, "shortName"), XposedHelpers.getObjectField(app, "pid"));
XposedHelpers.callMethod(param.thisObject, "bringDownServiceLocked", sr);
} else if (!allowRestart) {
XposedHelpers.callMethod(param.thisObject, "bringDownServiceLocked", sr);
} else {
boolean canceled = (Boolean) XposedHelpers.callMethod(param.thisObject, "scheduleServiceRestartLocked", sr, true);
// Should the service remain running? Note
// that in the
// extreme case of so many attempts to
// deliver a command
// that it failed we also will stop it here.
if (XposedHelpers.getBooleanField(sr, "startRequested") && (XposedHelpers.getBooleanField(sr, "stopIfKilled") || canceled)) {
Object pendingStarts = XposedHelpers.getObjectField(sr, "pendingStarts");
if ((Integer) XposedHelpers.callMethod(pendingStarts, "size") == 0) {
XposedHelpers.setBooleanField(sr, "startRequested", false);
if (XposedHelpers.getObjectField(sr, "tracker") != null) {
Object tracker = XposedHelpers.getObjectField(sr, "tracker");
Object mAm = XposedHelpers.getObjectField(param.thisObject, "mAm");
Object mProcessStats = XposedHelpers.getObjectField(mAm, "mProcessStats");
XposedHelpers.callMethod(tracker, "setStarted", false, XposedHelpers.callMethod(mProcessStats, "getMemFactorLocked"), SystemClock.uptimeMillis());
}
if (!XposedHelpers.getBooleanField(sr, "hasAutoCreateConnections")) {
// Whoops, no reason to restart!
XposedHelpers.callMethod(param.thisObject, "bringDownServiceLocked", sr);
}
}
}
}
}
if (!allowRestart) {
Object app_services = XposedHelpers.getObjectField(app, "services");
XposedHelpers.callMethod(app_services, "clear");
// Make sure there are no more restarting
// services for this
// process.
Object mRestartingServices = XposedHelpers.getObjectField(param.thisObject, "mRestartingServices");
for (int i = (Integer) XposedHelpers.callMethod(mRestartingServices, "size") - 1; i >= 0; i--) {
Object r = XposedHelpers.callMethod(mRestartingServices, "get", i);
String processName = (String) XposedHelpers.getObjectField(r, "processName");
Object serviceInfo = XposedHelpers.getObjectField(r, "serviceInfo");
Object applicationInfo = XposedHelpers.getObjectField(serviceInfo, "applicationInfo");
Object info = XposedHelpers.getObjectField(app, "info");
if (processName.equals((String) XposedHelpers.getObjectField(app, "processName")) && XposedHelpers.getIntField(applicationInfo, "uid") == XposedHelpers.getIntField(info, "uid")) {
XposedHelpers.callMethod(mRestartingServices, "remove", i);
XposedHelpers.callMethod(param.thisObject, "clearRestartingIfNeededLocked", r);
}
}
Object mPendingServices = XposedHelpers.getObjectField(param.thisObject, "mPendingServices");
for (int i = (Integer) XposedHelpers.callMethod(mPendingServices, "size") - 1; i >= 0; i--) {
Object r = XposedHelpers.callMethod(mPendingServices, "get", i);
String processName = (String) XposedHelpers.getObjectField(r, "processName");
Object serviceInfo = XposedHelpers.getObjectField(r, "serviceInfo");
Object applicationInfo = XposedHelpers.getObjectField(serviceInfo, "applicationInfo");
Object info = XposedHelpers.getObjectField(app, "info");
if (processName.equals((String) XposedHelpers.getObjectField(app, "processName")) && XposedHelpers.getIntField(applicationInfo, "uid") == XposedHelpers.getIntField(info, "uid")) {
XposedHelpers.callMethod(mPendingServices, "remove", i);
}
}
}
// Make sure we have no more records on the stopping
// list.
Object mDestroyingServices = XposedHelpers.getObjectField(param.thisObject, "mDestroyingServices");
int i = (Integer) XposedHelpers.callMethod(mDestroyingServices, "size");
while (i > 0) {
i--;
Object sr = XposedHelpers.callMethod(mDestroyingServices, "get", i);
if (XposedHelpers.getObjectField(sr, "app") == app) {
XposedHelpers.callMethod(sr, "forceClearTracker");
XposedHelpers.callMethod(mDestroyingServices, "remove", i);
if (DEBUG_SERVICE)
Slog.v(TAG, "killServices remove destroying " + sr);
}
}
Object executingServices = XposedHelpers.getObjectField(app, "executingServices");
XposedHelpers.callMethod(executingServices, "clear");
return null;
}
});
} catch (Throwable t) {
XposedBridge.log(t);
}
}
}