2 * Copyright (C) 2015 The CyanogenMod Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.settings.cmstats;
19 import android.app.job.JobParameters;
20 import android.app.job.JobService;
21 import android.net.Uri;
22 import android.os.AsyncTask;
23 import android.os.PersistableBundle;
24 import android.util.ArrayMap;
25 import android.util.Log;
26 import com.android.settings.R;
27 import org.json.JSONException;
28 import org.json.JSONObject;
30 import java.io.BufferedInputStream;
31 import java.io.BufferedReader;
32 import java.io.BufferedWriter;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.InputStreamReader;
36 import java.io.OutputStream;
37 import java.io.OutputStreamWriter;
38 import java.net.HttpURLConnection;
40 import java.util.Collections;
43 public class StatsUploadJobService extends JobService {
45 private static final String TAG = StatsUploadJobService.class.getSimpleName();
46 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
48 public static final String KEY_JOB_TYPE = "job_type";
49 public static final int JOB_TYPE_CYANOGEN = 1;
50 public static final int JOB_TYPE_CMORG = 2;
52 public static final String KEY_UNIQUE_ID = "uniqueId";
53 public static final String KEY_DEVICE_NAME = "deviceName";
54 public static final String KEY_VERSION = "version";
55 public static final String KEY_COUNTRY = "country";
56 public static final String KEY_CARRIER = "carrier";
57 public static final String KEY_CARRIER_ID = "carrierId";
58 public static final String KEY_TIMESTAMP = "timeStamp";
59 public static final String KEY_OPT_OUT = "optOut";
61 private final Map<JobParameters, StatsUploadTask> mCurrentJobs
62 = Collections.synchronizedMap(new ArrayMap<JobParameters, StatsUploadTask>());
65 public boolean onStartJob(JobParameters jobParameters) {
67 Log.d(TAG, "onStartJob() called with " + "jobParameters = [" + jobParameters + "]");
68 final StatsUploadTask uploadTask = new StatsUploadTask(jobParameters);
69 mCurrentJobs.put(jobParameters, uploadTask);
70 uploadTask.execute((Void) null);
75 public boolean onStopJob(JobParameters jobParameters) {
77 Log.d(TAG, "onStopJob() called with " + "jobParameters = [" + jobParameters + "]");
79 final StatsUploadTask cancelledJob;
80 cancelledJob = mCurrentJobs.remove(jobParameters);
82 if (cancelledJob != null) {
83 // cancel the ongoing background task
84 cancelledJob.cancel(true);
85 return true; // reschedule
91 private class StatsUploadTask extends AsyncTask<Void, Void, Boolean> {
93 private JobParameters mJobParams;
95 public StatsUploadTask(JobParameters jobParams) {
96 this.mJobParams = jobParams;
100 protected Boolean doInBackground(Void... params) {
102 PersistableBundle extras = mJobParams.getExtras();
104 String deviceId = extras.getString(KEY_UNIQUE_ID);
105 String deviceName = extras.getString(KEY_DEVICE_NAME);
106 String deviceVersion = extras.getString(KEY_VERSION);
107 String deviceCountry = extras.getString(KEY_COUNTRY);
108 String deviceCarrier = extras.getString(KEY_CARRIER);
109 String deviceCarrierId = extras.getString(KEY_CARRIER_ID);
110 long timeStamp = extras.getLong(KEY_TIMESTAMP);
111 boolean optOut = extras.getBoolean(KEY_OPT_OUT);
113 boolean success = false;
114 int jobType = extras.getInt(KEY_JOB_TYPE, -1);
115 if (!isCancelled()) {
117 case JOB_TYPE_CYANOGEN:
119 JSONObject json = new JSONObject();
120 json.put("optOut", optOut);
121 json.put("uniqueId", deviceId);
122 json.put("deviceName", deviceName);
123 json.put("version", deviceVersion);
124 json.put("country", deviceCountry);
125 json.put("carrier", deviceCarrier);
126 json.put("carrierId", deviceCarrierId);
127 json.put("timestamp", timeStamp);
129 success = uploadToCyanogen(json);
130 } catch (IOException | JSONException e) {
131 Log.e(TAG, "Could not upload stats checkin to cyanogen server", e);
138 success = uploadToCM(deviceId, deviceName, deviceVersion, deviceCountry,
139 deviceCarrier, deviceCarrierId, optOut);
140 } catch (IOException e) {
141 Log.e(TAG, "Could not upload stats checkin to commnity server", e);
148 Log.d(TAG, "job id " + mJobParams.getJobId() + ", has finished with success="
154 protected void onPostExecute(Boolean success) {
155 mCurrentJobs.remove(mJobParams);
156 jobFinished(mJobParams, !success);
161 private boolean uploadToCM(String deviceId, String deviceName, String deviceVersion,
162 String deviceCountry, String deviceCarrier, String deviceCarrierId,
166 final Uri uri = Uri.parse(getString(R.string.stats_cm_url)).buildUpon()
167 .appendQueryParameter("opt_out", optOut ? "1" : "0")
168 .appendQueryParameter("device_hash", deviceId)
169 .appendQueryParameter("device_name", deviceName)
170 .appendQueryParameter("device_version", deviceVersion)
171 .appendQueryParameter("device_country", deviceCountry)
172 .appendQueryParameter("device_carrier", deviceCarrier)
173 .appendQueryParameter("device_carrier_id", deviceCarrierId).build();
174 URL url = new URL(uri.toString());
175 HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
177 urlConnection.setInstanceFollowRedirects(true);
178 urlConnection.setDoOutput(true);
179 urlConnection.connect();
181 final int responseCode = urlConnection.getResponseCode();
182 if (DEBUG) Log.d(TAG, "cm server response code=" + responseCode);
183 final boolean success = responseCode == HttpURLConnection.HTTP_OK;
185 Log.w(TAG, "failed sending, server returned: " + getResponse(urlConnection,
190 urlConnection.disconnect();
195 private boolean uploadToCyanogen(JSONObject json)
196 throws IOException, JSONException {
197 String authToken = getAuthToken();
199 if (authToken.isEmpty()) {
200 Log.w(TAG, "no auth token!");
203 URL url = new URL(getString(R.string.stats_cyanogen_url));
204 HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
206 urlConnection.setInstanceFollowRedirects(true);
207 urlConnection.setDoInput(true);
208 urlConnection.setDoOutput(true);
210 urlConnection.setRequestProperty("Accept-Encoding", "identity");
211 urlConnection.setRequestProperty("Authorization", authToken);
212 urlConnection.setRequestProperty("Content-Type", "application/json");
214 OutputStream os = urlConnection.getOutputStream();
215 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
216 writer.write(json.toString());
221 urlConnection.connect();
223 final int responseCode = urlConnection.getResponseCode();
224 final boolean success = responseCode == HttpURLConnection.HTTP_OK;
226 final String response = getResponse(urlConnection, !success);
228 Log.d(TAG, "server responseCode: " + responseCode +", response=" + response);
231 Log.w(TAG, "failed sending, server returned: " + response);
235 urlConnection.disconnect();
239 private String getAuthToken() {
240 HttpURLConnection urlConnection = null;
242 URL url = new URL(getString(R.string.stats_cyanogen_token_url));
243 urlConnection = (HttpURLConnection) url.openConnection();
244 urlConnection.setInstanceFollowRedirects(true);
245 urlConnection.setDoInput(true);
247 urlConnection.setRequestProperty("Accept-Encoding", "identity");
248 urlConnection.setRequestProperty("Content-Type", "text/plain");
250 urlConnection.connect();
252 final int responseCode = urlConnection.getResponseCode();
253 final boolean success = responseCode == HttpURLConnection.HTTP_OK;
254 if (DEBUG) Log.d(TAG, "server auth response code=" + responseCode);
255 final String response = getResponse(urlConnection, !success);
257 Log.d(TAG, "server auth response=" + response);
262 } catch (IOException e) {
263 Log.e(TAG, "error getting auth token", e);
265 if (urlConnection != null) {
266 urlConnection.disconnect();
272 private String getResponse(HttpURLConnection httpUrlConnection, boolean errorStream)
274 InputStream responseStream = new BufferedInputStream(errorStream
275 ? httpUrlConnection.getErrorStream()
276 : httpUrlConnection.getInputStream());
278 BufferedReader responseStreamReader = new BufferedReader(
279 new InputStreamReader(responseStream));
281 StringBuilder stringBuilder = new StringBuilder();
282 while ((line = responseStreamReader.readLine()) != null) {
283 stringBuilder.append(line).append("\n");
285 responseStreamReader.close();
286 responseStream.close();
288 return stringBuilder.toString();