org.tecrash.crashreport.DropboxUploadingJob.java Source code

Java tutorial

Introduction

Here is the source code for org.tecrash.crashreport.DropboxUploadingJob.java

Source

/*
 * The MIT License (MIT)
 * Copyright (c) 2014 He Xiaocong (xiaocong@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
 * OR OTHER DEALINGS IN THE SOFTWARE.
 */

package org.tecrash.crashreport;

import android.content.Context;
import android.os.Build;
import android.os.DropBoxManager;
import android.os.SystemClock;

import com.path.android.jobqueue.Job;
import com.path.android.jobqueue.Params;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;

import org.tecrash.crashreport.api.IDropboxService;
import org.tecrash.crashreport.data.ReportDatas;
import org.tecrash.crashreport.util.Logger;
import org.tecrash.crashreport.util.Util;

import java.io.File;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import retrofit.ErrorHandler;
import retrofit.RestAdapter;
import retrofit.RetrofitError;
import retrofit.client.OkClient;
import retrofit.mime.TypedFile;

public class DropboxUploadingJob extends Job {
    static final long serialVersionUID = 0x2F3C0888L;
    private static final int MAX_DIG_LEN = 2 * 1024;
    private static Logger logger = Logger.getLogger();
    private long timestamp;
    private String incremental;

    public DropboxUploadingJob(long timestamp, String incremental) {
        super(new Params(100).requireNetwork().setGroupId("Dropbox").setPersistent(true)
                .setDelayMs(Util.getMaxDelayTimes()));

        this.timestamp = timestamp;
        this.incremental = incremental;
    }

    @Override
    public void onAdded() {
    }

    @Override
    public void onRun() throws Throwable {
        long last = Util.getLastEntryTimestamp(); // ??
        if (!Build.VERSION.INCREMENTAL.equals(incremental)) {
            // ??drpbox entry??
            long bootTime = System.currentTimeMillis() - SystemClock.elapsedRealtime();
            if (bootTime > last) {
                last = bootTime;
                Util.setLastEntryTimestamp(last);
            }
        }
        //        if (last >= timestamp) {
        //            logger.d("Cancelled as it was reported before!");
        //            return;
        //        }
        if (!Util.isEnabled()) {
            logger.d("Disabled so cancel it!");
            Util.setLastEntryTimestamp(last);
            return;
        }

        DropBoxManager dbm = (DropBoxManager) ReportApp.getInstance().getSystemService(Context.DROPBOX_SERVICE);
        List<ReportDatas.Entry> datas = new ArrayList<ReportDatas.Entry>();
        List<Long> timestamps = new ArrayList<Long>();
        List<String> tags = new ArrayList<String>();
        List<Long> entryTimestamps = new ArrayList<Long>();

        for (String tag : Util.getTags().keySet()) {
            DropBoxManager.Entry entry = dbm.getNextEntry(tag, last);
            while (entry != null) {
                ReportDatas.Entry data = convertToReportEntry(entry);
                if (data != null) {
                    boolean found = false;
                    for (ReportDatas.Entry d : datas) {
                        if (d.tag.equals(data.tag) && d.app.equals(data.app)) {
                            d.data.count += data.data.count;
                            if (d.data.count > 5)
                                d.data.count = 5;
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        datas.add(data);
                        timestamps.add(last);
                        tags.add(tag);
                    }
                }
                last = entry.getTimeMillis();
                entryTimestamps.add(last);
                entry = dbm.getNextEntry(tag, last);
            }
            //set back to last saved, for next tag
            last = Util.getLastEntryTimestamp();
        }

        IDropboxService service = getReportService(Util.getURL());

        // report dropbox entries
        ReportDatas.ReportResults results = service.report(Util.getKey(), Util.getUserAgent(),
                new ReportDatas(datas));

        //set the latest entry's timestamp as last
        if (!entryTimestamps.isEmpty()) {
            Collections.sort(entryTimestamps);
            last = entryTimestamps.get(entryTimestamps.size() - 1);
        }
        // save where to upload next time.
        Util.setLastEntryTimestamp(last);

        //check whether to report full dropbox entry content and log
        if (shouldReportDetail()) {
            for (int i = 0; i < results.data.length; i++) {
                ReportDatas.Result result = results.data[i];
                ReportDatas.Entry data = datas.get(i);
                if (result != null && result.dropbox_id != null && result.dropbox_id.length() > 0) {
                    DropBoxManager.Entry entry = dbm.getNextEntry(tags.get(i), timestamps.get(i));
                    // use okhttp to gzip content
                    OkHttpClient client = new OkHttpClient();
                    client.networkInterceptors().add(new GzipRequestInterceptor());
                    RequestBody requestBody = new StreamRequestBody(entry.getInputStream());
                    Request request = new Request.Builder()
                            .url(Util.getURL() + "/dropbox/" + result.dropbox_id + "/content")
                            .header("Authorization", Util.getKey()).post(requestBody).build();
                    client.newCall(request).execute();
                }
            }
            IDropboxService uploadService = getReportService(Util.getUploadURL());
            for (int i = 0; i < results.data.length; i++) {
                ReportDatas.Result result = results.data[i];
                if (result != null && result.dropbox_id != null && result.dropbox_id.length() > 0) { // server received the data
                    // upload attachment
                    ReportDatas.Entry data = datas.get(i);
                    if (data.data.log != null && data.data.log.length() > 0
                            && (data.data.log.endsWith(".gz") || data.data.log.endsWith(".zip"))) {
                        File file = new File(data.data.log);
                        if (file.exists()) {
                            uploadService.uploadAttachment(Util.getKey(), result.dropbox_id,
                                    new TypedFile("application/zip", file));
                        }
                    }
                }
            }
        }
        logger.d("** Total %d Dropbox entries added!", results.data.length);
    }

    private IDropboxService getReportService(String endpoint) {
        RestAdapter restAdapter = new RestAdapter.Builder().setErrorHandler(new ErrorHandler() {
            @Override
            public Throwable handleError(RetrofitError cause) {
                logger.e("Error during send report:");
                logger.e(cause.toString());
                return cause;
            }
        }).setClient(new OkClient(getClient()))
                .setLogLevel(logger.isDebugEnabled() ? RestAdapter.LogLevel.BASIC : RestAdapter.LogLevel.NONE)
                .setEndpoint(endpoint).build();
        return restAdapter.create(IDropboxService.class);
    }

    private ReportDatas.Entry convertToReportEntry(DropBoxManager.Entry entry) throws IOException {
        ReportDatas.Entry data = null;
        if ((entry.getFlags() & DropBoxManager.IS_TEXT) != 0) {
            data = new ReportDatas.Entry();
            data.occurred_at = entry.getTimeMillis();
            data.tag = entry.getTag();
            String digest = entry.getText(MAX_DIG_LEN);
            data.app = processName(entry.getTag(), digest);
            data.data.log = logPath(entry.getTag(), digest);
        }
        return data;
    }

    private boolean shouldReportDetail() {
        return System.currentTimeMillis() - Build.TIME < 1000 * 3600 * 24 * Util.getDismissDays();
    }

    @Override
    protected void onCancel() {

    }

    @Override
    protected boolean shouldReRunOnThrowable(Throwable throwable) {
        return false;
    }

    //    /**
    //     * inputstream to string utf-8?
    //     */
    //    private String convertStreamToString(InputStream is)
    //            throws UnsupportedEncodingException {
    //        BufferedInputStream bis = new BufferedInputStream(is);
    //        InputStreamReader inputStreamReader = new InputStreamReader(bis, "utf-8");
    //        BufferedReader br = new BufferedReader(inputStreamReader);
    //        StringBuilder sb = new StringBuilder();
    //        try {
    //            String line;
    //            while ((line = br.readLine()) != null) {
    //                sb.append(line);
    //                sb.append("\n");
    //            }
    //        } catch (IOException e) {
    //        } finally {
    //            try {
    //                is.close();
    //            } catch (IOException e) {
    //            }
    //        }
    //        return sb.toString();
    //    }

    private String processName(String tag, String content) {
        if (Util.getTags().containsKey(tag))
            return Util.getTags().get(tag).getProcessName(tag, content);
        return null;
    }

    private String logPath(String tag, String content) {
        if (Util.getTags().containsKey(tag))
            return Util.getTags().get(tag).getLogPath(tag, content);
        return null;
    }

    private OkHttpClient getClient() {
        OkHttpClient client = new OkHttpClient();
        //        client.networkInterceptors().add(new GzipRequestInterceptor());
        client.setHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String s, SSLSession sslSession) {
                return true;
            }
        });
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");

            // set up a TrustManager that trusts everything
            sslContext.init(null, new TrustManager[] { new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                }

                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                }
            } }, new SecureRandom());

            SSLSocketFactory sf = sslContext.getSocketFactory();
            client.setSslSocketFactory(sf);
        } catch (NoSuchAlgorithmException e) {
        } catch (KeyManagementException e) {
        }
        return client;
    }
}