Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(198)

Side by Side Diff: android_webview/java/src/org/chromium/android_webview/AwVariationsSeedFetchService.java

Issue 2975693002: Add AwVariationsSeedFetchService and refactory VariationsSeedFetcher (Closed)
Patch Set: Update for comments for Patch 22 Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « android_webview/java/DEPS ('k') | android_webview/javatests/DEPS » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.android_webview;
6
7 import android.annotation.TargetApi;
8 import android.app.job.JobParameters;
9 import android.app.job.JobService;
10 import android.os.AsyncTask;
11 import android.os.Build;
12
13 import org.chromium.base.ContextUtils;
14 import org.chromium.base.Log;
15 import org.chromium.base.ThreadUtils;
16 import org.chromium.base.VisibleForTesting;
17 import org.chromium.base.annotations.SuppressFBWarnings;
18 import org.chromium.components.variations.firstrun.VariationsSeedFetcher;
19 import org.chromium.components.variations.firstrun.VariationsSeedFetcher.SeedInf o;
20
21 import java.io.Closeable;
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.ObjectInputStream;
27 import java.io.ObjectOutputStream;
28 import java.io.Serializable;
29 import java.util.concurrent.locks.Lock;
30 import java.util.concurrent.locks.ReentrantLock;
31
32 /**
33 * AwVariationsSeedFetchService is a Job Service to fetch test seed data which i s used by Finch
34 * to enable AB testing experiments in the native code. The fetched data is stor ed in the local
35 * directory which belongs to the Service process. This a prototype of the Varia tions Seed Fetch
36 * Service which is one part of the work of adding Finch to Android WebView.
37 */
38 @TargetApi(Build.VERSION_CODES.LOLLIPOP) // JobService requires API level 21.
39 public class AwVariationsSeedFetchService extends JobService {
40 private static final String TAG = "AwVartnsSeedFetchSvc";
41
42 public static final String WEBVIEW_VARIATIONS_DIR = "WebView_Variations/";
43 public static final String SEED_DATA_FILENAME = "variations_seed_data";
44 public static final String SEED_PREF_FILENAME = "variations_seed_pref";
45
46 // Synchronization lock to prevent simultaneous local seed file writing.
47 private static final Lock sLock = new ReentrantLock();
48
49 @Override
50 public boolean onStartJob(JobParameters params) {
51 // Ensure we can use ContextUtils later on.
52 ContextUtils.initApplicationContext(this.getApplicationContext());
53 new FetchFinchSeedDataTask(params).execute();
54 return true;
55 }
56
57 @Override
58 public boolean onStopJob(JobParameters params) {
59 // This method is called by the JobScheduler to stop a job before it has finished.
60 // Return true here to reschedule the job.
61 return true;
62 }
63
64 private class FetchFinchSeedDataTask extends AsyncTask<Void, Void, Void> {
65 private JobParameters mJobParams;
66
67 FetchFinchSeedDataTask(JobParameters params) {
68 mJobParams = params;
69 }
70
71 @Override
72 protected Void doInBackground(Void... params) {
73 fetchVariationsSeed();
74 return null;
75 }
76
77 @Override
78 protected void onPostExecute(Void success) {
79 jobFinished(mJobParams, false /* false -> don't reschedule */);
80 }
81 }
82
83 private static void fetchVariationsSeed() {
84 assert !ThreadUtils.runningOnUiThread();
85 // TryLock will drop calls from other threads when there is a thread exe cuting the function.
86 // TODO(yiyuny): Add explicitly control to ensure there's only one threa ding fetching at a
87 // time and that the seed doesn't get fetched too frequently.
88 if (sLock.tryLock()) {
89 try {
90 SeedInfo seedInfo = VariationsSeedFetcher.get().downloadContent(
91 VariationsSeedFetcher.VariationsPlatform.ANDROID_WEBVIEW , "");
92 storeVariationsSeed(seedInfo);
93 } catch (IOException e) {
94 // Exceptions are handled and logged in the downloadContent meth od, so we don't
95 // need any exception handling here. The only reason we need a c atch-statement here
96 // is because those exceptions are re-thrown from downloadConten t to skip the
97 // normal logic flow within that method.
98 } finally {
99 sLock.unlock();
100 }
101 }
102 }
103
104 /**
105 * SeedPreference is used to serialize/deserialize related fields of seed da ta when reading or
106 * writing them to the internal storage.
107 */
108 public static class SeedPreference implements Serializable {
109 /**
110 * Let the program deserialize the data when the fields are changed.
111 */
112 private static final long serialVersionUID = 0L;
113
114 public final String signature;
115 public final String country;
116 public final String date;
117 public final boolean isGzipCompressed;
118
119 public SeedPreference(SeedInfo seedInfo) {
120 signature = seedInfo.signature;
121 country = seedInfo.country;
122 date = seedInfo.date;
123 isGzipCompressed = seedInfo.isGzipCompressed;
124 }
125 }
126
127 private static File getOrCreateWebViewVariationsDir() throws IOException {
128 File webViewFileDir = ContextUtils.getApplicationContext().getFilesDir() ;
129 File dir = new File(webViewFileDir, WEBVIEW_VARIATIONS_DIR);
130 if (dir.mkdir() || dir.isDirectory()) {
131 return dir;
132 }
133 throw new IOException("Failed to get or create the WebView variations di rectory.");
134 }
135
136 /**
137 * Store the variations seed data and its related header fields into two sep arate files in the
138 * directory of Android WebView.
139 * @param seedInfo The seed data and its related header fields fetched from the finch server.
140 */
141 @VisibleForTesting
142 public static void storeVariationsSeed(SeedInfo seedInfo) {
143 FileOutputStream fosSeedData = null;
144 ObjectOutputStream oosSeedPref = null;
145 try {
146 File webViewVariationsDir = getOrCreateWebViewVariationsDir();
147 File seedDataFile = File.createTempFile(SEED_DATA_FILENAME, null, we bViewVariationsDir);
148 fosSeedData = new FileOutputStream(seedDataFile);
149 fosSeedData.write(seedInfo.seedData, 0, seedInfo.seedData.length);
150 renameTempFile(seedDataFile, new File(webViewVariationsDir, SEED_DAT A_FILENAME));
151 // Store separately so that reading large seed data (which is expens ive) can be
152 // prevented when checking the last seed fetch time.
153 File seedPrefFile = File.createTempFile(SEED_PREF_FILENAME, null, we bViewVariationsDir);
154 oosSeedPref = new ObjectOutputStream(new FileOutputStream(seedPrefFi le));
155 oosSeedPref.writeObject(new SeedPreference(seedInfo));
156 renameTempFile(seedPrefFile, new File(webViewVariationsDir, SEED_PRE F_FILENAME));
157 } catch (IOException e) {
158 Log.e(TAG, "Failed to write variations seed data or preference to a file." + e);
159 } finally {
160 closeStream(fosSeedData);
161 closeStream(oosSeedPref);
162 }
163 }
164
165 /**
166 * Get the variations seed data from the file in the internal storage.
167 * @return The byte array which contains the seed data.
168 * @throws IOException if fail to get or create the WebView Variations direc tory.
169 */
170 @VisibleForTesting
171 public static byte[] getVariationsSeedData() throws IOException {
172 FileInputStream fisSeedData = null;
173 try {
174 File webViewVariationsDir = getOrCreateWebViewVariationsDir();
175 fisSeedData = new FileInputStream(new File(webViewVariationsDir, SEE D_DATA_FILENAME));
176 return VariationsSeedFetcher.convertInputStreamToByteArray(fisSeedDa ta);
177 } finally {
178 if (fisSeedData != null) {
179 fisSeedData.close();
180 }
181 }
182 }
183
184 /**
185 * Get the variations seed preference from the file in the internal storage.
186 * @return The seed preference which holds related header fields of the seed .
187 * @throws IOException if fail to get or create the WebView Variations direc tory.
188 * @throws ClassNotFoundException if fail to load the class of the serialize d object.
189 */
190 @VisibleForTesting
191 public static SeedPreference getVariationsSeedPreference()
192 throws IOException, ClassNotFoundException {
193 ObjectInputStream oisSeedPref = null;
194 try {
195 File webViewVariationsDir = getOrCreateWebViewVariationsDir();
196 oisSeedPref = new ObjectInputStream(
197 new FileInputStream(new File(webViewVariationsDir, SEED_PREF _FILENAME)));
198 return (SeedPreference) oisSeedPref.readObject();
199 } finally {
200 if (oisSeedPref != null) {
201 oisSeedPref.close();
202 }
203 }
204 }
205
206 /**
207 * Clear the test data.
208 * @throws IOException if fail to get or create the WebView Variations direc tory.
209 */
210 @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE") // ignoring File .delete() return
211 @VisibleForTesting
212 public static void clearDataForTesting() throws IOException {
213 File webViewVariationsDir = getOrCreateWebViewVariationsDir();
214 File seedDataFile = new File(webViewVariationsDir, SEED_DATA_FILENAME);
215 File seedPrefFile = new File(webViewVariationsDir, SEED_PREF_FILENAME);
216 seedDataFile.delete();
217 seedPrefFile.delete();
218 webViewVariationsDir.delete();
219 }
220
221 @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE") // ignoring File .delete() return
paulmiller 2017/07/20 18:06:20 renameTo also returns success/fail, yes?
yiyuny 2017/07/20 18:20:45 Done.
222 private static void renameTempFile(File tempFile, File newFile) {
223 newFile.delete();
224 tempFile.renameTo(newFile);
225 }
226
227 private static void closeStream(Closeable stream) {
228 if (stream != null) {
229 try {
230 stream.close();
231 } catch (IOException e) {
232 Log.e(TAG, "Failed to close stream." + e);
paulmiller 2017/07/20 18:06:20 might want a space after the .
yiyuny 2017/07/20 18:20:45 Done.
233 }
234 }
235 }
236 }
OLDNEW
« no previous file with comments | « android_webview/java/DEPS ('k') | android_webview/javatests/DEPS » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698