blob: af2e1746d586e05fc71bbde936c70ad2b0153995 [file] [log] [blame]
package com.google.android.hiddenapi.testapp;
import android.app.Activity;
import android.os.Bundle;
import android.os.StrictMode;
import android.os.strictmode.Violation;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import dalvik.system.VMRuntime;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MainActivity extends Activity implements OnClickListener {
enum AppStrictMode {
OFF,
LOG,
DEATH,
CALLBACK;
private static AppStrictMode[] vals = values();
public AppStrictMode next()
{
return vals[(this.ordinal()+1) % vals.length];
}
}
private final StrictMode.OnVmViolationListener mViolationListener = (v) -> onVmViolation(v);
private TextView mTextView;
private TextView mCurrentStrictMode;
private TextView mStrictModeText;
private AppStrictMode mCurrentMode = AppStrictMode.OFF;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = findViewById(R.id.textView);
mCurrentStrictMode = findViewById(R.id.strict_mode);
mStrictModeText = findViewById(R.id.strict_mode_text);
setAllButtonClickListeners(findViewById(R.id.layout));
setStrictMode(AppStrictMode.OFF);
}
private void setAllButtonClickListeners(View v) {
if (v instanceof Button) {
v.setOnClickListener(this);
} else if (v instanceof ViewGroup) {
ViewGroup vg = (ViewGroup) v;
for (int i = 0; i < vg.getChildCount(); i++) {
setAllButtonClickListeners(vg.getChildAt(i));
}
}
}
private void onVmViolation(Violation v) {
setStrictModeText(toString(v));
}
private void setStrictModeText(String s) {
if (TextUtils.isEmpty(s)) {
mStrictModeText.setText("");
mStrictModeText.setVisibility(View.GONE);
} else {
mStrictModeText.setText(s);
mStrictModeText.setVisibility(View.VISIBLE);
}
}
private void setStrictMode(AppStrictMode mode) {
StrictMode.VmPolicy policy;
switch (mode) {
case OFF:
policy = new StrictMode.VmPolicy.Builder().permitNonSdkApiUsage().build();
break;
case LOG:
policy = new StrictMode.VmPolicy.Builder().detectNonSdkApiUsage().penaltyLog().build();
break;
case DEATH:
policy = new StrictMode.VmPolicy.Builder().detectNonSdkApiUsage().penaltyDeath().build();
break;
case CALLBACK:
policy = new StrictMode.VmPolicy.Builder()
.detectNonSdkApiUsage()
.penaltyListener(r -> mStrictModeText.post(r), mViolationListener)
.build();
break;
default:
return;
}
mCurrentMode = mode;
StrictMode.setVmPolicy(policy);
mCurrentStrictMode.setText("StrictMode: " + mode);
}
@Override
public void onClick(View view) {
setStrictModeText(null);
switch (view.getId()) {
case R.id.disable_checks_reflection:
try {
tryDisableApiChecksReflectively();
mTextView.setText("Ok \uD83D\uDE00");
} catch (Exception e) {
handleException(e);
}
break;
case R.id.disable_checks_linking:
try {
tryDisableApiChecksLinking();
} catch (LinkageError e) {
handleException(e);
}
break;
case R.id.strict_mode:
setStrictMode(mCurrentMode.next());
break;
default:
String name = ((TextView) view).getText().toString();
accessActivityMember(name);
break;
}
}
private void accessActivityMember(String name) {
try {
Field f = Activity.class.getDeclaredField(name);
f.setAccessible(true);
Object o = f.get(this);
mTextView.setText(String.format("%s: %s", name, o == null ? "null" : o.toString()));
} catch (NoSuchFieldException e) {
handleException(e);
} catch (IllegalAccessException e) {
handleException(e);
}
}
private void handleException(Throwable e) {
Log.e(getClass().getSimpleName(), "Failed", e);
mTextView.setText(toString(e));
}
private static String toString(Throwable t) {
StringWriter s = new StringWriter();
t.printStackTrace(new PrintWriter(s));
return s.toString();
}
private static void tryDisableApiChecksReflectively()
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
IllegalAccessException {
Class vmRuntimeClass = Class.forName("dalvik.system.VMRuntime");
Method getRuntime = vmRuntimeClass.getDeclaredMethod("getRuntime");
Object vmRuntime = getRuntime.invoke(null);
Method setExemptions = vmRuntimeClass.getDeclaredMethod(
"setHiddenApiExemptions", String[].class);
setExemptions.invoke(vmRuntime, (Object) new String[]{"L"});
}
private static void tryDisableApiChecksLinking() {
VMRuntime.getRuntime().setHiddenApiExemptions(new String[]{"L"});
}
}