Android Open Source - bitfynd-wallet-android Crash Reporter






From Project

Back to project page bitfynd-wallet-android.

License

The source code is released under:

GNU General Public License

If you think the Android project bitfynd-wallet-android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright 2011-2014 the original author or authors.
 *//from  w  w  w  .  j  a v  a 2 s . c om
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package de.schildbach.wallet.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.Comparator;
import java.util.Formatter;
import java.util.List;
import java.util.Set;

import javax.annotation.Nonnull;

import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.core.Wallet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Build;

import com.google.common.base.Charsets;

import de.schildbach.wallet.Configuration;
import de.schildbach.wallet.Constants;
import de.schildbach.wallet.WalletApplication;

/**
 * @author Andreas Schildbach
 */
public class CrashReporter
{
  private static final String BACKGROUND_TRACES_FILENAME = "background.trace";
  private static final String CRASH_TRACE_FILENAME = "crash.trace";

  private static final long TIME_CREATE_APPLICATION = System.currentTimeMillis();

  private static File backgroundTracesFile;
  private static File crashTraceFile;

  private static final Logger log = LoggerFactory.getLogger(CrashReporter.class);

  public static void init(@Nonnull final File cacheDir)
  {
    backgroundTracesFile = new File(cacheDir, BACKGROUND_TRACES_FILENAME);
    crashTraceFile = new File(cacheDir, CRASH_TRACE_FILENAME);

    Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler(Thread.getDefaultUncaughtExceptionHandler()));
  }

  public static boolean hasSavedBackgroundTraces()
  {
    return backgroundTracesFile.exists();
  }

  public static void appendSavedBackgroundTraces(@Nonnull final Appendable report) throws IOException
  {
    BufferedReader reader = null;

    try
    {
      reader = new BufferedReader(new InputStreamReader(new FileInputStream(backgroundTracesFile), Charsets.UTF_8));
      copy(reader, report);
    }
    finally
    {
      if (reader != null)
        reader.close();

      backgroundTracesFile.delete();
    }
  }

  public static boolean hasSavedCrashTrace()
  {
    return crashTraceFile.exists();
  }

  public static void appendSavedCrashTrace(@Nonnull final Appendable report) throws IOException
  {
    BufferedReader reader = null;

    try
    {
      reader = new BufferedReader(new InputStreamReader(new FileInputStream(crashTraceFile), Charsets.UTF_8));
      copy(reader, report);
    }
    finally
    {
      if (reader != null)
        reader.close();

      crashTraceFile.delete();
    }
  }

  private static void copy(@Nonnull final BufferedReader in, @Nonnull final Appendable out) throws IOException
  {
    while (true)
    {
      final String line = in.readLine();
      if (line == null)
        break;

      out.append(line).append('\n');
    }
  }

  public static void appendDeviceInfo(@Nonnull final Appendable report, final Context context) throws IOException
  {
    final Resources res = context.getResources();
    final android.content.res.Configuration config = res.getConfiguration();
    final ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

    report.append("Device Model: " + android.os.Build.MODEL + "\n");
    report.append("Android Version: " + android.os.Build.VERSION.RELEASE + "\n");
    report.append("Board: " + android.os.Build.BOARD + "\n");
    report.append("Brand: " + android.os.Build.BRAND + "\n");
    report.append("Device: " + android.os.Build.DEVICE + "\n");
    report.append("Display: " + android.os.Build.DISPLAY + "\n");
    report.append("Finger Print: " + android.os.Build.FINGERPRINT + "\n");
    report.append("Host: " + android.os.Build.HOST + "\n");
    report.append("ID: " + android.os.Build.ID + "\n");
    // report.append("Manufacturer: " + manufacturer + "\n");
    report.append("Product: " + android.os.Build.PRODUCT + "\n");
    report.append("Tags: " + android.os.Build.TAGS + "\n");
    report.append("Time: " + android.os.Build.TIME + "\n");
    report.append("Type: " + android.os.Build.TYPE + "\n");
    report.append("User: " + android.os.Build.USER + "\n");
    report.append("Configuration: " + config + "\n");
    report.append("Screen Layout: size " + (config.screenLayout & android.content.res.Configuration.SCREENLAYOUT_SIZE_MASK) + " long "
        + (config.screenLayout & android.content.res.Configuration.SCREENLAYOUT_LONG_MASK) + "\n");
    report.append("Display Metrics: " + res.getDisplayMetrics() + "\n");
    report.append("Memory Class: " + activityManager.getMemoryClass()
        + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? "/" + largeMemoryClass(activityManager) : "") + "\n");
  }

  private static int largeMemoryClass(@Nonnull final ActivityManager activityManager)
  {
    try
    {
      return (Integer) ActivityManager.class.getMethod("getLargeMemoryClass").invoke(activityManager);
    }
    catch (final Exception x)
    {
      throw new RuntimeException(x);
    }
  }

  public static void appendInstalledPackages(@Nonnull final Appendable report, final Context context) throws IOException
  {
    final PackageManager pm = context.getPackageManager();
    final List<PackageInfo> installedPackages = pm.getInstalledPackages(0);

    // sort by package name
    Collections.sort(installedPackages, new Comparator<PackageInfo>()
    {
      @Override
      public int compare(final PackageInfo lhs, final PackageInfo rhs)
      {
        return lhs.packageName.compareTo(rhs.packageName);
      }
    });

    for (final PackageInfo p : installedPackages)
      report.append(String.format("%s %s (%d) - %tF %tF\n", p.packageName, p.versionName, p.versionCode, p.firstInstallTime, p.lastUpdateTime));
  }

  public static void appendApplicationInfo(@Nonnull final Appendable report, @Nonnull final WalletApplication application) throws IOException
  {
    final PackageInfo pi = application.packageInfo();
    final Configuration configuration = application.getConfiguration();
    final long now = System.currentTimeMillis();

    report.append("Version: " + pi.versionName + " (" + pi.versionCode + ")\n");
    report.append("Package: " + pi.packageName + "\n");
    report.append("Test/Prod: " + (Constants.TEST ? "test" : "prod") + "\n");
    report.append("Time: " + String.format("%tF %tT %tz", now, now, now) + "\n");
    report.append("Time of launch: " + String.format("%tF %tT %tz", TIME_CREATE_APPLICATION, TIME_CREATE_APPLICATION, TIME_CREATE_APPLICATION)
        + "\n");
    report.append("Time of last update: " + String.format("%tF %tT %tz", pi.lastUpdateTime, pi.lastUpdateTime, pi.lastUpdateTime) + "\n");
    report.append("Time of first install: " + String.format("%tF %tT %tz", pi.firstInstallTime, pi.firstInstallTime, pi.firstInstallTime) + "\n");
    final long lastBackupTime = configuration.getLastBackupTime();
    report.append("Time of backup: "
        + (lastBackupTime > 0 ? String.format("%tF %tT %tz", lastBackupTime, lastBackupTime, lastBackupTime) : "none") + "\n");
    report.append("Network: " + Constants.NETWORK_PARAMETERS.getId() + "\n");
    final Wallet wallet = application.getWallet();
    report.append("Encrypted: " + wallet.isEncrypted() + "\n");
    report.append("Keychain size: " + wallet.getKeychainSize() + "\n");

    final Set<Transaction> transactions = wallet.getTransactions(true);
    int numInputs = 0;
    int numOutputs = 0;
    int numSpentOutputs = 0;
    for (final Transaction tx : transactions)
    {
      numInputs += tx.getInputs().size();
      final List<TransactionOutput> outputs = tx.getOutputs();
      numOutputs += outputs.size();
      for (final TransactionOutput txout : outputs)
      {
        if (!txout.isAvailableForSpending())
          numSpentOutputs++;
      }
    }
    report.append("Transactions: " + transactions.size() + "\n");
    report.append("Inputs: " + numInputs + "\n");
    report.append("Outputs: " + numOutputs + " (spent: " + numSpentOutputs + ")\n");
    report.append("Last block seen: " + wallet.getLastBlockSeenHeight() + " (" + wallet.getLastBlockSeenHash() + ")\n");

    report.append("Databases:");
    for (final String db : application.databaseList())
      report.append(" " + db);
    report.append("\n");

    final File filesDir = application.getFilesDir();
    report.append("\nContents of FilesDir " + filesDir + ":\n");
    appendDir(report, filesDir, 0);
    final File logDir = application.getDir("log", Context.MODE_PRIVATE);
    report.append("\nContents of LogDir " + logDir + ":\n");
    appendDir(report, logDir, 0);
  }

  private static void appendDir(@Nonnull final Appendable report, @Nonnull final File file, final int indent) throws IOException
  {
    for (int i = 0; i < indent; i++)
      report.append("  - ");

    final Formatter formatter = new Formatter(report);
    formatter.format("%tF %tT %8d  %s\n", file.lastModified(), file.lastModified(), file.length(), file.getName());
    formatter.close();

    if (file.isDirectory())
      for (final File f : file.listFiles())
        appendDir(report, f, indent + 1);
  }

  public static void saveBackgroundTrace(@Nonnull final Throwable throwable, @Nonnull final PackageInfo packageInfo)
  {
    synchronized (backgroundTracesFile)
    {
      PrintWriter writer = null;

      try
      {
        writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(backgroundTracesFile, true), Charsets.UTF_8));

        final long now = System.currentTimeMillis();
        writer.println(String.format("\n--- collected at %tF %tT %tz on version %s (%d)", now, now, now, packageInfo.versionName,
            packageInfo.versionCode));
        appendTrace(writer, throwable);
      }
      catch (final IOException x)
      {
        log.error("problem writing background trace", x);
      }
      finally
      {
        if (writer != null)
          writer.close();
      }
    }
  }

  private static void appendTrace(@Nonnull final PrintWriter writer, @Nonnull final Throwable throwable)
  {
    throwable.printStackTrace(writer);
    // If the exception was thrown in a background thread inside
    // AsyncTask, then the actual exception can be found with getCause
    Throwable cause = throwable.getCause();
    while (cause != null)
    {
      writer.println("\nCause:\n");
      cause.printStackTrace(writer);
      cause = cause.getCause();
    }
  }

  private static class ExceptionHandler implements Thread.UncaughtExceptionHandler
  {
    private final Thread.UncaughtExceptionHandler previousHandler;

    public ExceptionHandler(@Nonnull final Thread.UncaughtExceptionHandler previousHandler)
    {
      this.previousHandler = previousHandler;
    }

    @Override
    public synchronized void uncaughtException(final Thread t, final Throwable exception)
    {
      log.warn("crashing because of uncaught exception", exception);

      try
      {
        saveCrashTrace(exception);
      }
      catch (final IOException x)
      {
        log.info("problem writing crash trace", x);
      }

      previousHandler.uncaughtException(t, exception);
    }

    private void saveCrashTrace(@Nonnull final Throwable throwable) throws IOException
    {
      final PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(crashTraceFile), Charsets.UTF_8));
      appendTrace(writer, throwable);
      writer.close();
    }
  }
}




Java Source Code List

de.schildbach.wallet.AddressBookProvider.java
de.schildbach.wallet.Configuration.java
de.schildbach.wallet.Constants.java
de.schildbach.wallet.ExchangeRatesProvider.java
de.schildbach.wallet.FileAttachmentProvider.java
de.schildbach.wallet.WalletApplication.java
de.schildbach.wallet.WalletBalanceWidgetProvider.java
de.schildbach.wallet.camera.CameraManager.java
de.schildbach.wallet.data.PaymentIntent.java
de.schildbach.wallet.integration.android.BitcoinIntegration.java
de.schildbach.wallet.offline.AcceptBluetoothService.java
de.schildbach.wallet.offline.AcceptBluetoothThread.java
de.schildbach.wallet.offline.DirectPaymentTask.java
de.schildbach.wallet.service.AutosyncReceiver.java
de.schildbach.wallet.service.BlockchainServiceImpl.java
de.schildbach.wallet.service.BlockchainService.java
de.schildbach.wallet.service.BlockchainStateLoader.java
de.schildbach.wallet.service.BlockchainState.java
de.schildbach.wallet.service.UpgradeWalletService.java
de.schildbach.wallet.ui.AbstractBindServiceActivity.java
de.schildbach.wallet.ui.AbstractWalletActivity.java
de.schildbach.wallet.ui.AddressAndLabel.java
de.schildbach.wallet.ui.AddressBookActivity.java
de.schildbach.wallet.ui.BlockListFragment.java
de.schildbach.wallet.ui.CurrencyAmountView.java
de.schildbach.wallet.ui.CurrencyCalculatorLink.java
de.schildbach.wallet.ui.CurrencySymbolDrawable.java
de.schildbach.wallet.ui.CurrencyTextView.java
de.schildbach.wallet.ui.DialogBuilder.java
de.schildbach.wallet.ui.EditAddressBookEntryFragment.java
de.schildbach.wallet.ui.EncryptKeysDialogFragment.java
de.schildbach.wallet.ui.ExchangeRateLoader.java
de.schildbach.wallet.ui.ExchangeRatesActivity.java
de.schildbach.wallet.ui.ExchangeRatesFragment.java
de.schildbach.wallet.ui.FancyListFragment.java
de.schildbach.wallet.ui.FileAdapter.java
de.schildbach.wallet.ui.HelpDialogFragment.java
de.schildbach.wallet.ui.ImportDialogButtonEnablerListener.java
de.schildbach.wallet.ui.InputParser.java
de.schildbach.wallet.ui.MaybeMaintenanceFragment.java
de.schildbach.wallet.ui.NetworkMonitorActivity.java
de.schildbach.wallet.ui.PeerListFragment.java
de.schildbach.wallet.ui.ProgressDialogFragment.java
de.schildbach.wallet.ui.ReportIssueDialogBuilder.java
de.schildbach.wallet.ui.RequestCoinsActivity.java
de.schildbach.wallet.ui.RequestCoinsFragment.java
de.schildbach.wallet.ui.RestoreWalletActivity.java
de.schildbach.wallet.ui.ScanActivity.java
de.schildbach.wallet.ui.ScannerView.java
de.schildbach.wallet.ui.SendCoinsQrActivity.java
de.schildbach.wallet.ui.SendingAddressesFragment.java
de.schildbach.wallet.ui.ShowPasswordCheckListener.java
de.schildbach.wallet.ui.TransactionsListAdapter.java
de.schildbach.wallet.ui.TransactionsListFragment.java
de.schildbach.wallet.ui.WalletActionsFragment.java
de.schildbach.wallet.ui.WalletActivity.java
de.schildbach.wallet.ui.WalletAddressFragment.java
de.schildbach.wallet.ui.WalletAddressesAdapter.java
de.schildbach.wallet.ui.WalletAddressesFragment.java
de.schildbach.wallet.ui.WalletBalanceFragment.java
de.schildbach.wallet.ui.WalletBalanceLoader.java
de.schildbach.wallet.ui.WalletDisclaimerFragment.java
de.schildbach.wallet.ui.WalletTransactionsFragment.java
de.schildbach.wallet.ui.preference.AboutFragment.java
de.schildbach.wallet.ui.preference.DiagnosticsFragment.java
de.schildbach.wallet.ui.preference.PreferenceActivity.java
de.schildbach.wallet.ui.preference.SettingsFragment.java
de.schildbach.wallet.ui.send.DecodePrivateKeyTask.java
de.schildbach.wallet.ui.send.DeriveKeyTask.java
de.schildbach.wallet.ui.send.MaintenanceDialogFragment.java
de.schildbach.wallet.ui.send.RequestPaymentRequestTask.java
de.schildbach.wallet.ui.send.RequestWalletBalanceTask.java
de.schildbach.wallet.ui.send.SendCoinsActivity.java
de.schildbach.wallet.ui.send.SendCoinsFragment.java
de.schildbach.wallet.ui.send.SendCoinsOfflineTask.java
de.schildbach.wallet.ui.send.SweepWalletActivity.java
de.schildbach.wallet.ui.send.SweepWalletFragment.java
de.schildbach.wallet.util.Base43.java
de.schildbach.wallet.util.BitmapFragment.java
de.schildbach.wallet.util.Bluetooth.java
de.schildbach.wallet.util.CircularProgressView.java
de.schildbach.wallet.util.CrashReporter.java
de.schildbach.wallet.util.Crypto.java
de.schildbach.wallet.util.Formats.java
de.schildbach.wallet.util.GenericUtils.java
de.schildbach.wallet.util.HttpGetThread.java
de.schildbach.wallet.util.Io.java
de.schildbach.wallet.util.Iso8601Format.java
de.schildbach.wallet.util.LinuxSecureRandom.java
de.schildbach.wallet.util.MonetarySpannable.java
de.schildbach.wallet.util.Nfc.java
de.schildbach.wallet.util.Qr.java
de.schildbach.wallet.util.ThrottlingWalletChangeListener.java
de.schildbach.wallet.util.ViewPagerTabs.java
de.schildbach.wallet.util.WalletUtils.java
de.schildbach.wallet.util.WholeStringBuilder.java