Добрый день! Имеется старый проект QEMU for Android, который не обновлялся с 2010 года (то есть почти 8 лет). Соответственно, проект не имеет ни Runtime Permissions, ни сертификата второго уровня. Требуется заставить работать это приложение на Android Marshmallow, для начала неплохо было бы внедрить хотя бы Runtime Permissions.
В первую очередь я попробовал декомпилировать проект через Virtuos Ten Studio, чтобы узнать версию используемой Activity
(именно эта программа, так как она смогла разобрать и собрать этот проект, после маленькой редакции smali-кода). На выходе получил это в методе onCreate
в первой активности, которая стартует (код немного обрезан, так как целиком не влез):
.method public onCreate(Landroid/os/Bundle;)V
.locals 11
.param p1, "savedInstanceState" # Landroid/os/Bundle;
.prologue
const/4 v8, 0x1
const/4 v9, 0x0
const-string v10, "Ok"
const-string v7, "Error"
.line 178
const/4 v4, 0x0
.line 179
.local v4, "vers":I
invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
.line 180
invoke-static {v8}, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;
move-result-object v0
.line 192
.local v0, "Ok":Ljava/lang/Boolean;
:try_start_0
invoke-static {}, LlibSDL/jni/libSDLproxy;->libSDLcheckloaded()I
:try_end_0
.catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_0} :catch_0
move-result v4
.line 202
:goto_0
invoke-virtual {v0}, Ljava/lang/Boolean;->booleanValue()Z
invoke-virtual {v5}, Ljava/lang/Boolean;->booleanValue()Z
move-result v5
if-nez v5, :cond_2
.line 224
iget-object v5, p0, LlibSDL/jni/libSDL;->sManager:Landroid/hardware/SensorManager;
invoke-virtual {v5, v8}, Landroid/hardware/SensorManager;->getSensorList(I)Ljava/util/List;
move-result-object v3
.line 225
.local v3, "liste":Ljava/util/List;, "Ljava/util/List<Landroid/hardware/Sensor;>;"
const/4 v1, 0x0
.local v1, "a":I
:goto_2
invoke-interface {v3}, Ljava/util/List;->size()I
move-result v5
if-lt v1, v5, :cond_3
.line 230
.end local v1 # "a":I
.end local v3 # "liste":Ljava/util/List;, "Ljava/util/List<Landroid/hardware/Sensor;>;"
:cond_2
invoke-virtual {p0, v9}, LlibSDL/jni/libSDL;->setDefaultKeyMode(I)V
.line 231
sget v5, LlibSDL/jni/libSDLconfig;->CONF_DEFAULT_ORIENTATION:I
invoke-virtual {p0, v5}, LlibSDL/jni/libSDL;->setRequestedOrientation(I)V
goto :goto_1
.line 226
.restart local v1 # "a":I
.restart local v3 # "liste":Ljava/util/List;, "Ljava/util/List<Landroid/hardware/Sensor;>;"
:cond_3
sget-object v6, Ljava/lang/System;->out:Ljava/io/PrintStream;
new-instance v5, Ljava/lang/StringBuilder;
const-string v7, "Sensor "
invoke-direct {v5, v7}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
invoke-virtual {v5, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
move-result-object v5
const-string v7, ": "
invoke-virtual {v5, v7}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v7
invoke-interface {v3, v1}, Ljava/util/List;->get(I)Ljava/lang/Object;
move-result-object v5
check-cast v5, Landroid/hardware/Sensor;
invoke-virtual {v5}, Landroid/hardware/Sensor;->getName()Ljava/lang/String;
move-result-object v5
invoke-virtual {v7, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v5
invoke-virtual {v5}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v5
invoke-virtual {v6, v5}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
.line 227
iget-object v6, p0, LlibSDL/jni/libSDL;->sManager:Landroid/hardware/SensorManager;
iget-object v7, p0, LlibSDL/jni/libSDL;->sensorEventListener:Landroid/hardware/SensorEventListener;
invoke-interface {v3, v9}, Ljava/util/List;->get(I)Ljava/lang/Object;
move-result-object v5
check-cast v5, Landroid/hardware/Sensor;
const/4 v8, 0x3
invoke-virtual {v6, v7, v5, v8}, Landroid/hardware/SensorManager;->registerListener(Landroid/hardware/SensorEventListener;Landroid/hardware/Sensor;I)Z
.line 225
add-int/lit8 v1, v1, 0x1
goto :goto_2
.end method
Много неразберихи, но я обнаружил, что сгенерировался Java-код. Уже лучше. Я взял весь код и закинул в Android Studio, добавив сверху NDK и нативную библиотеку, которая была в декомпилированном приложении. Однако, код оказался не совсем рабочим. Вот такое содержимое получилось в onCreate
:
public void onCreate(final Bundle bundle) {
super.onCreate(bundle);
Boolean b = true;
Label_0115:
while (true) {
try {
final int libSDLcheckloaded = libSDLproxy.libSDLcheckloaded();
if (b) {
if (libSDLcheckloaded == 2) {
break Label_0115;
}
new AlertDialog.Builder((Context) this).setTitle((CharSequence) "Error").setMessage((CharSequence) "Incompatible SDL library version").setNeutralButton((CharSequence) "Ok", (DialogInterface$OnClickListener) new DialogInterface$OnClickListener() {
public void onClick(final DialogInterface dialogInterface, final int n) {
libSDL.this.finish();
}
}).show();
}
return;
} catch (Throwable t) {
b = false;
new AlertDialog.Builder((Context) this).setTitle((CharSequence) "Error").setMessage((CharSequence) "Cannot load SDL library").setNeutralButton((CharSequence) "Ok", (DialogInterface$OnClickListener) new DialogInterface$OnClickListener() {
public void onClick(final DialogInterface dialogInterface, final int n) {
libSDL.this.finish();
}
}).show();
final int libSDLcheckloaded = 0;
continue;
}
break;
}
this.requestWindowFeature(1);
this.getWindow().setFlags(1024, 1152);
this.setContentView((View) (this.SDLview = new libSDLview((Context) this)));
this.sManager = (SensorManager) this.getSystemService("sensor");
if (!libSDLconfig.CONF_DISABLE_ACCELEROMETER) {
final List sensorList = this.sManager.getSensorList(1);
for (int i = 0; i < sensorList.size(); ++i) {
System.out.println("Sensor " + i + ": " + sensorList.get(i).getName());
this.sManager.registerListener(this.sensorEventListener, (Sensor) sensorList.get(0), 3);
}
}
this.setDefaultKeyMode(0);
this.setRequestedOrientation(libSDLconfig.CONF_DEFAULT_ORIENTATION);
}
И самое важное, что я узнал — версию используемой Activity
из строки:
import android.app.Activity;
То есть библиотека поддержки v4 или v7 не используется, а метод для запроса разрешений в реальном времени есть в классе ContextCompat
, который содержится в библиотеке поддержки v4.
Так же в Java-коде был вот такой вот интересный метод, где каждый continue
вызывает ошибку "not a loop statement" (незначительная часть кода убрана, так как целиком он просто не влезал):
public libSDL() {
super();
this.MouseMode = 1;
this.oldSimLeft = false;
this.oldSimRight = false;
this.oldSimUp = false;
this.oldSimDown = false;
this.TrackballKillMoves = false;
this.TP_DeltaX = 0;
this.TP_DeltaY = 0;
this.sensorEventListener = (SensorEventListener) new SensorEventListener() {
public void onAccuracyChanged(final Sensor sensor, final int n) {
}
public void onSensorChanged(final SensorEvent sensorEvent) {
float n;
float n2 = 0.0f;
float n3 = 0.0f;
Boolean oldSimRight;
int n4;
Boolean oldSimDown;
Boolean oldSimUp;
int n5;
int n6;
Boolean b;
Boolean b2;
Boolean oldSimLeft;
int n7;
Block_34_Outer:
Label_0339_Outer:
while (true) {
Label_0332:
while (true) {
Label_0302:
Label_0242_Outer:
Label_0272_Outer:
while (true) {
Label_0272:
while (true) {
Label_0242:
Label_0037_Outer:
while (true) {
while (true) {
Label_0339:
Block_8_Outer:
Label_0428_Outer:
while (true) {
synchronized (this) {
n = sensorEvent.values[0];
n2 = sensorEvent.values[1];
n3 = sensorEvent.values[2];
if (n < 0.0f) {
n = -n;
}
break Label_0339;
while (true) {
Block_29:
while (true) {
Label_0080:
while (true) {
Block_6:
while (true) {
Label_0249:
{
Block_21:
{
while (true) {
Block_14:
{
Block_7:
{
Label_0403:
{
Label_0160:
{
while (true) {
while (true) {
Label_0279:
{
Block_18_Outer:
while (true) {
while (true) {
Block_17:
{
while (true) {
Block_24:
{
while (true) {
while (true) {
while (true) {
Label_0309:
while (true) {
oldSimRight = true;
break Label_0160;
libSDLproxy.libSDLnotifyjoystick(-(int) (3276.0f * sensorEvent.values[0]) - libSDLconfig.CONF_JOYSTICK_Y_DELTA, -(int) (3276.0f * sensorEvent.values[1]), -1);
break Label_0339;
libSDLproxy.libSDLnotifykey(n4, 19);
break Label_0309;
oldSimDown = true;
break Label_0403;
while (true) {
oldSimUp = true;
break Label_0210;
libSDLproxy.libSDLnotifykey(n5, 20);
break Label_0339;
break Block_17;
break Block_21;
n6 = 1;
break Label_0242;
continue Label_0210_Outer;
}
n5 = 1;
continue Label_0332;
libSDLproxy.libSDLnotifykey(n6, 21);
break Label_0249;
n4 = 1;
continue Label_0302;
break Label_0210_Outer;
continue Block_34_Outer;
}
break Block_24;
break Block_33;
continue Label_0242_Outer;
}
Label_0378:
{
continue Label_0210_Outer;
}
}
oldSimLeft = true;
continue Block_18_Outer;
}
}
continue Block_23_Outer;
}
}
continue Block_31_Outer;
}
libSDLproxy.libSDLnotifykey(n7, 22);
break Label_0279;
continue Block_8_Outer;
}
libSDL.this.oldSimLeft = oldSimLeft;
libSDL.this.oldSimRight = oldSimRight;
libSDL.this.oldSimUp = oldSimUp;
libSDL.this.oldSimDown = oldSimDown;
return;
}
}
oldSimRight = true;
continue Label_0210;
}
Label_0481:
{
continue Label_0339_Outer;
}
}
oldSimLeft = true;
continue Label_0272_Outer;
}
b2 = false;
b = false;
break Block_6;
}
oldSimDown = true;
continue Block_8_Outer;
}
}
n7 = 1;
continue Label_0272;
}
continue Label_0242_Outer;
}
b2 = true;
continue Label_0037_Outer;
}
oldSimLeft = false;
oldSimRight = false;
oldSimUp = false;
oldSimDown = false;
continue Label_0272_Outer;
}
oldSimUp = true;
continue Label_0037_Outer;
}
}
Label_0525:
{
libSDLproxy.libSDLnotifyjoystick((int) (3276.0f * sensorEvent.values[1]) - libSDLconfig.CONF_JOYSTICK_Y_DELTA, (int) (3276.0f * sensorEvent.values[0]), -1);
}
continue Label_0339;
}
if (n2 < 0.0f) {
n2 = -n2;
}
if (n3 < 0.0f) {
continue;
}
continue;
}
Label_0582:
{
n6 = 0;
}
continue Label_0242;
}
Label_0588:
{
n7 = 0;
}
continue Label_0272;
}
Label_0594:
{
n4 = 0;
}
continue Label_0302;
}
Label_0600:
{
n5 = 0;
}
continue Label_0332;
}
}
}
}
;
}
И еще несколько native
методов, которые тоже отмечались ошибкой:
public static native int libSDLcheckloaded();
public static native void libSDLcleanup();
public static native int libSDLisportrait();
public static native int libSDLmain(final String p0, final String p1);
public static native void libSDLnotifyjoystick(final int p0, final int p1, final int p2);
public static native void libSDLnotifykey(final int p0, final int p1);
public static native void libSDLnotifytouch(final int p0, final int p1, final int p2, final int p3);
public static native void libSDLnotifytrackpad(final int p0, final int p1, final int p2, final int p3);
public static native void libSDLpause();
public static native void libSDLresume();
public static native int libSDLupdatebuffer(final Buffer p0, final int p1, final int p2);
Вопрос: реально ли обновить этот проект для работы на Android M (а потом и O), не затрачивая на это месяцы? И, если да — как именно внедрять Runtime Permissions с остальными возможностями новых версий Android'a?
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Есть некая таблица с данными о работникахSLQ запрос выводит данные об определенных работниках