OSDN Git Service

Merge tag 'android-6.0.1_r74' into HEAD
[android-x86/packages-apps-Settings.git] / src / com / android / settings / cmstats / StatsUploadJobService.java
1 /*
2  * Copyright (C) 2015 The CyanogenMod Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.android.settings.cmstats;
18
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;
29
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;
39 import java.net.URL;
40 import java.util.Collections;
41 import java.util.Map;
42
43 public class StatsUploadJobService extends JobService {
44
45     private static final String TAG = StatsUploadJobService.class.getSimpleName();
46     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
47
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;
51
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";
60
61     private final Map<JobParameters, StatsUploadTask> mCurrentJobs
62             = Collections.synchronizedMap(new ArrayMap<JobParameters, StatsUploadTask>());
63
64     @Override
65     public boolean onStartJob(JobParameters jobParameters) {
66         if (DEBUG)
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);
71         return true;
72     }
73
74     @Override
75     public boolean onStopJob(JobParameters jobParameters) {
76         if (DEBUG)
77             Log.d(TAG, "onStopJob() called with " + "jobParameters = [" + jobParameters + "]");
78
79         final StatsUploadTask cancelledJob;
80         cancelledJob = mCurrentJobs.remove(jobParameters);
81
82         if (cancelledJob != null) {
83             // cancel the ongoing background task
84             cancelledJob.cancel(true);
85             return true; // reschedule
86         }
87
88         return false;
89     }
90
91     private class StatsUploadTask extends AsyncTask<Void, Void, Boolean> {
92
93         private JobParameters mJobParams;
94
95         public StatsUploadTask(JobParameters jobParams) {
96             this.mJobParams = jobParams;
97         }
98
99         @Override
100         protected Boolean doInBackground(Void... params) {
101
102             PersistableBundle extras = mJobParams.getExtras();
103
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);
112
113             boolean success = false;
114             int jobType = extras.getInt(KEY_JOB_TYPE, -1);
115             if (!isCancelled()) {
116                 switch (jobType) {
117                     case JOB_TYPE_CYANOGEN:
118                         try {
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);
128
129                             success = uploadToCyanogen(json);
130                         } catch (IOException | JSONException e) {
131                             Log.e(TAG, "Could not upload stats checkin to cyanogen server", e);
132                             success = false;
133                         }
134                         break;
135
136                     case JOB_TYPE_CMORG:
137                         try {
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);
142                             success = false;
143                         }
144                         break;
145                 }
146             }
147             if (DEBUG)
148                 Log.d(TAG, "job id " + mJobParams.getJobId() + ", has finished with success="
149                         + success);
150             return success;
151         }
152
153         @Override
154         protected void onPostExecute(Boolean success) {
155             mCurrentJobs.remove(mJobParams);
156             jobFinished(mJobParams, !success);
157         }
158     }
159
160
161     private boolean uploadToCM(String deviceId, String deviceName, String deviceVersion,
162                                String deviceCountry, String deviceCarrier, String deviceCarrierId,
163                                boolean optOut)
164             throws IOException {
165
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();
176         try {
177             urlConnection.setInstanceFollowRedirects(true);
178             urlConnection.setDoOutput(true);
179             urlConnection.connect();
180
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;
184             if (!success) {
185                 Log.w(TAG, "failed sending, server returned: " + getResponse(urlConnection,
186                         !success));
187             }
188             return success;
189         } finally {
190             urlConnection.disconnect();
191         }
192
193     }
194
195     private boolean uploadToCyanogen(JSONObject json)
196             throws IOException, JSONException {
197         String authToken = getAuthToken();
198
199         if (authToken.isEmpty()) {
200             Log.w(TAG, "no auth token!");
201         }
202
203         URL url = new URL(getString(R.string.stats_cyanogen_url));
204         HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
205         try {
206             urlConnection.setInstanceFollowRedirects(true);
207             urlConnection.setDoInput(true);
208             urlConnection.setDoOutput(true);
209
210             urlConnection.setRequestProperty("Accept-Encoding", "identity");
211             urlConnection.setRequestProperty("Authorization", authToken);
212             urlConnection.setRequestProperty("Content-Type", "application/json");
213
214             OutputStream os = urlConnection.getOutputStream();
215             BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
216             writer.write(json.toString());
217             writer.flush();
218             writer.close();
219             os.close();
220
221             urlConnection.connect();
222
223             final int responseCode = urlConnection.getResponseCode();
224             final boolean success = responseCode == HttpURLConnection.HTTP_OK;
225
226             final String response = getResponse(urlConnection, !success);
227             if (DEBUG)
228                 Log.d(TAG, "server responseCode: " + responseCode +", response=" + response);
229
230             if (!success) {
231                 Log.w(TAG, "failed sending, server returned: " + response);
232             }
233             return success;
234         } finally {
235             urlConnection.disconnect();
236         }
237     }
238
239     private String getAuthToken() {
240         HttpURLConnection urlConnection = null;
241         try {
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);
246
247             urlConnection.setRequestProperty("Accept-Encoding", "identity");
248             urlConnection.setRequestProperty("Content-Type", "text/plain");
249
250             urlConnection.connect();
251
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);
256             if (DEBUG)
257                 Log.d(TAG, "server auth response=" + response);
258
259             if (success) {
260                 return response;
261             }
262         } catch (IOException e) {
263             Log.e(TAG, "error getting auth token", e);
264         } finally {
265             if (urlConnection != null) {
266                 urlConnection.disconnect();
267             }
268         }
269         return "";
270     }
271
272     private String getResponse(HttpURLConnection httpUrlConnection, boolean errorStream)
273             throws IOException {
274         InputStream responseStream = new BufferedInputStream(errorStream
275                 ? httpUrlConnection.getErrorStream()
276                 : httpUrlConnection.getInputStream());
277
278         BufferedReader responseStreamReader = new BufferedReader(
279                 new InputStreamReader(responseStream));
280         String line = "";
281         StringBuilder stringBuilder = new StringBuilder();
282         while ((line = responseStreamReader.readLine()) != null) {
283             stringBuilder.append(line).append("\n");
284         }
285         responseStreamReader.close();
286         responseStream.close();
287
288         return stringBuilder.toString();
289     }
290
291 }