blob: f5a532592af033ed15513cd8c2305cdc70edcc69 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package io.v.android.debug;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.support.annotation.Nullable;
import android.util.Log;
import java.io.IOException;
import io.v.android.error.ErrorReporter;
import io.v.android.error.ToastingErrorReporter;
import io.v.v23.android.R;
import lombok.experimental.UtilityClass;
@UtilityClass
public class Debug {
private static final String TAG = Debug.class.getSimpleName();
/**
* Determines whether the top-level apk was built in debug mode. This is preferable to
* {@code BuildConfig.DEBUG} as that is only available per module.
*/
public static boolean isApkDebug(final Context context) {
return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
}
/**
* Clears all data for this app. This will force the application to close. It would be nice to
* be able to schedule a restart as well, but clearing app data clears any scheduled intents.
* <p>
* When debugging Vanadium applications, this is often useful to clear the app blessings cache
* and Syncbase data.
*
* @param errorReporter the error reporter used to report any errors. If null,
* {@link ToastingErrorReporter#reportError(Context, int, Throwable)} is
* used.
*/
public static void clearAppData(final Context context,
@Nullable final ErrorReporter errorReporter) {
try {
Runtime.getRuntime().exec("pm clear " + context.getPackageName());
} catch (final IOException e) {
if (errorReporter == null) {
ToastingErrorReporter.reportError(context, R.string.err_app_clear, e);
} else {
errorReporter.onError(R.string.err_app_clear, e);
}
}
}
public static void stopPackageServices(final Context context) {
final PackageInfo pkg;
try {
pkg = context.getPackageManager().getPackageInfo(context.getPackageName(),
PackageManager.GET_SERVICES);
} catch (final PackageManager.NameNotFoundException e) {
Log.w(TAG, "Unable to enumerate package components", e);
return;
}
for (final ServiceInfo svc : pkg.services) {
context.stopService(new Intent().setClassName(context, svc.name));
}
}
/**
* Terminates the JVM for this app. When debugging Vanadium applications, this is useful for
* terminating any long-lived Android services that might be attached to the app process
* (e.g. Syncbase).
* <p>
* This additionally stops all services defined in the (merged) package manifest before
* terminating the process. Services default to {@link android.app.Service#START_STICKY}/{@link
* android.app.Service#START_STICKY_COMPATIBILITY}, which would result in started services
* auto-restarting after process termination. This could lead to unconventional initialization
* order, which is not something we necessarily want to exercise while debugging.
*/
public static void killProcess(final Context context) {
stopPackageServices(context);
System.exit(0);
}
public static void restartProcess(final Context context) {
final Intent i = context.getPackageManager().getLaunchIntentForPackage(
context.getPackageName());
context.startActivity(i);
killProcess(context);
}
}