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

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

Issue 2975693002: Add AwVariationsSeedFetchService and refactory VariationsSeedFetcher (Closed)
Patch Set: Add imports for SuppressFBWarnings 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.annotations.SuppressFBWarnings;
17 import org.chromium.components.variations.firstrun.VariationsSeedFetcher;
18 import org.chromium.components.variations.firstrun.VariationsSeedFetcher.SeedInf o;
19
20 import java.io.Closeable;
21 import java.io.File;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.io.ObjectOutputStream;
25 import java.io.Serializable;
26 import java.util.concurrent.locks.Lock;
27 import java.util.concurrent.locks.ReentrantLock;
28
29 /**
30 * AwVariationsSeedFetchService is a Job Service to fetch test seed data which i s used by Finch
31 * to enable AB testing experiments in the native code. The fetched data is stor ed in the local
32 * directory which belongs to the Service process.
33 */
34 @TargetApi(Build.VERSION_CODES.LOLLIPOP) // JobService requires API level 21.
35 public class AwVariationsSeedFetchService extends JobService {
36 private static final String TAG = "AwVartnsSeedFetchSvc";
37
38 public static final String WEBVIEW_VARIATIONS_DIR = "WebView_Variations/";
39 public static final String SEED_DATA_FILENAME = "variations_seed_data";
40 public static final String SEED_PREF_FILENAME = "variations_seed_pref";
41
42 // Synchronization lock to prevent simultaneous local seed file writing.
43 private static final Lock sLock = new ReentrantLock();
44
45 @Override
46 public boolean onStartJob(JobParameters params) {
47 // Ensure we can use ContextUtils later on.
48 ContextUtils.initApplicationContext(this.getApplicationContext());
49 new FetchFinchSeedDataTask(params).execute();
50 return true;
51 }
52
53 @Override
54 public boolean onStopJob(JobParameters params) {
55 // This method is called by the JobScheduler to stop a job before it has finished.
56 // Return true here to reschedule the job.
57 return true;
58 }
59
60 private class FetchFinchSeedDataTask extends AsyncTask<Void, Void, Void> {
61 private JobParameters mJobParams;
62
63 FetchFinchSeedDataTask(JobParameters params) {
64 mJobParams = params;
65 }
66
67 @Override
68 protected Void doInBackground(Void... params) {
69 AwVariationsSeedFetchService.fetchSeed();
70 return null;
71 }
72
73 @Override
74 protected void onPostExecute(Void success) {
75 jobFinished(mJobParams, false /* false -> don't reschedule */);
76 }
77 }
78
79 private static void fetchSeed() {
80 assert !ThreadUtils.runningOnUiThread();
81 // TryLock will drop calls from other threads when there is a thread exe cuting the function.
82 // TODO(yiyuny): Add explicitly control to ensure there's only one threa ding fetching at a
83 // time and that the seed doesn't get fetched too frequently
84 if (sLock.tryLock()) {
85 try {
86 SeedInfo seedInfo = VariationsSeedFetcher.get().downloadContent(
87 VariationsSeedFetcher.VariationsPlatform.ANDROID_WEBVIEW , "");
88 storeVariationsSeed(seedInfo);
89 } catch (IOException e) {
90 // Exceptions are handled and logged in the downloadContent meth od, so we don't
91 // need any exception handling here. The only reason we need a c atch-statement here
92 // is because those exceptions are re-thrown from downloadConten t to skip the
93 // normal logic flow within that method.
94 } finally {
95 sLock.unlock();
96 }
97 }
98 }
99
100 /**
101 * SeedPreference is used to serialize/deserialize related fields of seed da ta when reading or
102 * writing them to the internal storage.
103 */
104 public static class SeedPreference implements Serializable {
105 /**
106 * Let the program deserialize the data when the fields are changed.
107 */
108 private static final long serialVersionUID = 0L;
109
110 public final String signature;
111 public final String country;
112 public final String date;
113 public final boolean isGzipCompressed;
114
115 public SeedPreference(SeedInfo seedInfo) {
116 signature = seedInfo.signature;
117 country = seedInfo.country;
118 date = seedInfo.date;
119 isGzipCompressed = seedInfo.isGzipCompressed;
120 }
121 }
122
123 private static File getOrCreateWebViewVariationsDir() {
124 File webViewFileDir = ContextUtils.getApplicationContext().getFilesDir() ;
125 File dir = new File(webViewFileDir, WEBVIEW_VARIATIONS_DIR);
126 if (dir.mkdir() || dir.isDirectory()) {
127 return dir;
128 }
129 return null;
130 }
131
132 private static void storeVariationsSeed(SeedInfo seedInfo) {
133 File webViewVariationsDir = getOrCreateWebViewVariationsDir();
134 if (webViewVariationsDir == null) {
135 Log.e(TAG, "Failed to get or create the WebView variations directory .");
136 return;
137 }
138
139 FileOutputStream fosSeedData = null;
140 ObjectOutputStream oosSeedPref = null;
141 try {
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 @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE") // ignoring File .delete() return
161 private static void renameTempFile(File tempFile, File newFile) {
162 try {
163 newFile.delete();
164 tempFile.renameTo(newFile);
165 } catch (SecurityException e) {
gsennton 2017/07/17 14:32:10 Why are we catching SecurityException here? (it's
yiyuny 2017/07/17 16:37:06 Done.
166 Log.e(TAG, "Access denied when writing the file." + e);
167 } catch (NullPointerException e) {
168 Log.e(TAG, "File which will be renamed to is null." + e);
169 }
170 }
171
172 private static void closeStream(Closeable stream) {
173 if (stream != null) {
174 try {
175 stream.close();
176 } catch (IOException e) {
177 Log.e(TAG, "Failed to close stream." + e);
178 }
179 }
180 }
181 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698