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

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 code to delete test file. 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
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 AwVariationsSeedFetchService.fetchSeed();
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 fetchSeed() {
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 public 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 @VisibleForTesting
137 public static void storeVariationsSeed(SeedInfo seedInfo) {
138 FileOutputStream fosSeedData = null;
139 ObjectOutputStream oosSeedPref = null;
140 try {
141 File webViewVariationsDir = getOrCreateWebViewVariationsDir();
142 File seedDataFile = File.createTempFile(SEED_DATA_FILENAME, null, we bViewVariationsDir);
143 fosSeedData = new FileOutputStream(seedDataFile);
144 fosSeedData.write(seedInfo.seedData, 0, seedInfo.seedData.length);
145 renameTempFile(seedDataFile, new File(webViewVariationsDir, SEED_DAT A_FILENAME));
146 // Store separately so that reading large seed data (which is expens ive) can be
147 // prevented when checking the last seed fetch time.
148 File seedPrefFile = File.createTempFile(SEED_PREF_FILENAME, null, we bViewVariationsDir);
149 oosSeedPref = new ObjectOutputStream(new FileOutputStream(seedPrefFi le));
150 oosSeedPref.writeObject(new SeedPreference(seedInfo));
151 renameTempFile(seedPrefFile, new File(webViewVariationsDir, SEED_PRE F_FILENAME));
152 } catch (IOException e) {
153 Log.e(TAG, "Failed to write variations seed data or preference to a file." + e);
154 } finally {
155 closeStream(fosSeedData);
156 closeStream(oosSeedPref);
157 }
158 }
159
160 @VisibleForTesting
161 public static byte[] getVariationsSeedData() throws IOException {
162 FileInputStream fisSeedData = null;
163 try {
164 File webViewVariationsDir = getOrCreateWebViewVariationsDir();
165 fisSeedData = new FileInputStream(new File(webViewVariationsDir, SEE D_DATA_FILENAME));
166 return VariationsSeedFetcher.convertInputStreamToByteArray(fisSeedDa ta);
167 } finally {
168 if (fisSeedData != null) {
169 fisSeedData.close();
170 }
171 }
172 }
173
174 @VisibleForTesting
175 public static SeedPreference getVariationsSeedPreference()
Alexei Svitkine (slow) 2017/07/18 19:09:40 Public functions should have javadoc.
yiyuny 2017/07/18 21:44:58 Done.
176 throws IOException, ClassNotFoundException {
177 ObjectInputStream oisSeedPref = null;
178 try {
179 File webViewVariationsDir = getOrCreateWebViewVariationsDir();
180 oisSeedPref = new ObjectInputStream(
181 new FileInputStream(new File(webViewVariationsDir, SEED_PREF _FILENAME)));
182 return (SeedPreference) oisSeedPref.readObject();
183 } finally {
184 if (oisSeedPref != null) {
185 oisSeedPref.close();
186 }
187 }
188 }
189
190 @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE") // ignoring File .delete() return
191 private static void renameTempFile(File tempFile, File newFile) {
192 newFile.delete();
193 tempFile.renameTo(newFile);
194 }
195
196 private static void closeStream(Closeable stream) {
197 if (stream != null) {
198 try {
199 stream.close();
200 } catch (IOException e) {
201 Log.e(TAG, "Failed to close stream." + e);
202 }
203 }
204 }
205 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698