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

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProvider.java

Issue 2695113002: [Webview, Child Accounts] Automatically sign in to Chrome if needed. (Closed)
Patch Set: Fix instrumentation tests Created 3 years, 10 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
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser.superviseduser; 5 package org.chromium.chrome.browser.superviseduser;
6 6
7 import android.annotation.TargetApi; 7 import android.annotation.TargetApi;
8 import android.content.BroadcastReceiver; 8 import android.content.BroadcastReceiver;
9 import android.content.Context; 9 import android.content.Context;
10 import android.content.Intent; 10 import android.content.Intent;
11 import android.content.IntentFilter; 11 import android.content.IntentFilter;
12 import android.os.Build; 12 import android.os.Build;
13 import android.os.Bundle; 13 import android.os.Bundle;
14 import android.os.SystemClock; 14 import android.os.SystemClock;
15 import android.os.UserManager; 15 import android.os.UserManager;
16 16
17 import org.chromium.base.Callback;
17 import org.chromium.base.ThreadUtils; 18 import org.chromium.base.ThreadUtils;
18 import org.chromium.base.VisibleForTesting; 19 import org.chromium.base.VisibleForTesting;
19 import org.chromium.base.annotations.CalledByNative; 20 import org.chromium.base.annotations.CalledByNative;
20 import org.chromium.base.library_loader.LibraryLoader; 21 import org.chromium.base.library_loader.LibraryLoader;
21 import org.chromium.base.library_loader.ProcessInitException; 22 import org.chromium.base.library_loader.ProcessInitException;
22 import org.chromium.base.metrics.RecordHistogram; 23 import org.chromium.base.metrics.RecordHistogram;
24 import org.chromium.chrome.browser.childaccounts.ChildAccountService;
25 import org.chromium.chrome.browser.firstrun.ForcedSigninProcessor;
23 import org.chromium.chrome.browser.init.ChromeBrowserInitializer; 26 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
27 import org.chromium.components.signin.ChromeSigninController;
28 import org.chromium.components.supervisedusererrorpage.FilteringBehaviorReason;
24 import org.chromium.components.webrestrictions.browser.WebRestrictionsContentPro vider; 29 import org.chromium.components.webrestrictions.browser.WebRestrictionsContentPro vider;
25 30
26 import java.util.concurrent.ArrayBlockingQueue; 31 import java.util.concurrent.ArrayBlockingQueue;
27 import java.util.concurrent.BlockingQueue; 32 import java.util.concurrent.BlockingQueue;
28 import java.util.concurrent.TimeUnit; 33 import java.util.concurrent.TimeUnit;
29 34
30 /** 35 /**
31 * Content provider for telling other apps (e.g. WebView apps) about the supervi sed user URL filter. 36 * Content provider for telling other apps (e.g. WebView apps) about the supervi sed user URL filter.
32 */ 37 */
33 public class SupervisedUserContentProvider extends WebRestrictionsContentProvide r { 38 public class SupervisedUserContentProvider extends WebRestrictionsContentProvide r {
34 private static final String SUPERVISED_USER_CONTENT_PROVIDER_ENABLED = 39 private static final String SUPERVISED_USER_CONTENT_PROVIDER_ENABLED =
35 "SupervisedUserContentProviderEnabled"; 40 "SupervisedUserContentProviderEnabled";
36 private long mNativeSupervisedUserContentProvider; 41 private long mNativeSupervisedUserContentProvider;
37 private boolean mChromeAlreadyStarted; 42 private boolean mChromeAlreadyStarted;
38 private static Object sEnabledLock = new Object(); 43 private static Object sEnabledLock = new Object();
44 private static Object sContentProviderLock = new Object();
45
46 private static final String TAG = "SupervisedUserContent";
39 47
40 // Three value "boolean" caching enabled state, null if not yet known. 48 // Three value "boolean" caching enabled state, null if not yet known.
41 private static Boolean sEnabled; 49 private static Boolean sEnabled;
42 50
43 private long getSupervisedUserContentProvider() throws ProcessInitException { 51 @VisibleForTesting
44 mChromeAlreadyStarted = LibraryLoader.isInitialized(); 52 void startForcedSigninProcessor(Context appContext, Runnable onComplete) {
45 if (mNativeSupervisedUserContentProvider != 0) { 53 ForcedSigninProcessor.start(appContext, onComplete);
46 return mNativeSupervisedUserContentProvider;
47 }
48
49 ChromeBrowserInitializer.getInstance(getContext()).handleSynchronousStar tup();
50
51 mNativeSupervisedUserContentProvider = nativeCreateSupervisedUserContent Provider();
52 return mNativeSupervisedUserContentProvider;
53 } 54 }
54 55
55 void setNativeSupervisedUserContentProviderForTesting(long nativeProvider) { 56 @VisibleForTesting
56 mNativeSupervisedUserContentProvider = nativeProvider; 57 void listenForChildAccountStatusChange(Callback<Boolean> callback) {
58 ChildAccountService.listenForStatusChange(callback);
59 }
60
61 private long getSupervisedUserContentProvider() {
62 // This may lock for some time, but is always called on a background thr ead, and will only
63 // take significant time if the Chrome process isn't already running.
64 synchronized (sContentProviderLock) {
65 mChromeAlreadyStarted = LibraryLoader.isInitialized();
66 if (mNativeSupervisedUserContentProvider != 0) {
67 return mNativeSupervisedUserContentProvider;
68 }
69 final Context appContext = getContext().getApplicationContext();
70 final SupervisedUserReply<Long> reply = new SupervisedUserReply<>();
71 ThreadUtils.runOnUiThread(new Runnable() {
72 @Override
73 public void run() {
74 try {
75 ChromeBrowserInitializer.getInstance(appContext).handleS ynchronousStartup();
76 } catch (ProcessInitException e) {
77 reply.onQueryFinished(0L);
78 return;
79 }
80 final ChromeSigninController chromeSigninController =
81 ChromeSigninController.get(appContext);
82 if (chromeSigninController.isSignedIn()) {
83 reply.onQueryFinished(nativeCreateSupervisedUserContentP rovider());
84 return;
85 }
86 // Try to sign in, Chrome needs to be signed in to get the U RL filter.
87 startForcedSigninProcessor(appContext, new Runnable() {
88 @Override
89 public void run() {
90 if (!chromeSigninController.isSignedIn()) {
91 reply.onQueryFinished(0L);
92 return;
93 }
94 // Wait for the status change; Chrome can't check an y URLs until this
95 // has happened.
96 listenForChildAccountStatusChange(new Callback<Boole an>() {
97 @Override
98 public void onResult(Boolean result) {
99 reply.onQueryFinished(
100 nativeCreateSupervisedUserContentPro vider());
101 }
102 });
103 }
104 });
105 }
106 });
107 try {
108 Long result = reply.getResult();
109 if (result == null) return 0;
110 mNativeSupervisedUserContentProvider = result;
111 return mNativeSupervisedUserContentProvider;
112 } catch (InterruptedException e) {
113 return 0;
114 }
115 }
57 } 116 }
58 117
59 static class SupervisedUserReply<T> { 118 static class SupervisedUserReply<T> {
60 private static final long RESULT_TIMEOUT_SECONDS = 10; 119 private static final long RESULT_TIMEOUT_SECONDS = 10;
61 final BlockingQueue<T> mQueue = new ArrayBlockingQueue<>(1); 120 final BlockingQueue<T> mQueue = new ArrayBlockingQueue<>(1);
62 121
63 void onQueryFinished(T reply) { 122 void onQueryFinished(T reply) {
64 // This must be called precisely once per query. 123 // This must be called precisely once per query.
65 mQueue.add(reply); 124 mQueue.add(reply);
66 } 125 }
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 @Override 161 @Override
103 protected WebRestrictionsResult shouldProceed(final String url) { 162 protected WebRestrictionsResult shouldProceed(final String url) {
104 // This will be called on multiple threads (but never the UI thread), 163 // This will be called on multiple threads (but never the UI thread),
105 // see http://developer.android.com/guide/components/processes-and-threa ds.html#ThreadSafe. 164 // see http://developer.android.com/guide/components/processes-and-threa ds.html#ThreadSafe.
106 // The reply comes back on a different thread (possibly the UI thread) s ome time later. 165 // The reply comes back on a different thread (possibly the UI thread) s ome time later.
107 // As such it needs to correctly match the replies to the calls. It does this by creating a 166 // As such it needs to correctly match the replies to the calls. It does this by creating a
108 // reply object for each query, and passing this through the callback st ructure. The reply 167 // reply object for each query, and passing this through the callback st ructure. The reply
109 // object also handles waiting for the reply. 168 // object also handles waiting for the reply.
110 long startTimeMs = SystemClock.elapsedRealtime(); 169 long startTimeMs = SystemClock.elapsedRealtime();
111 final SupervisedUserQueryReply queryReply = new SupervisedUserQueryReply (); 170 final SupervisedUserQueryReply queryReply = new SupervisedUserQueryReply ();
171 final long contentProvider = getSupervisedUserContentProvider();
172 if (contentProvider == 0) {
173 return new WebRestrictionsResult(
174 false, new int[] {FilteringBehaviorReason.NOT_SIGNED_IN}, nu ll);
175 }
112 ThreadUtils.runOnUiThread(new Runnable() { 176 ThreadUtils.runOnUiThread(new Runnable() {
113 @Override 177 @Override
114 public void run() { 178 public void run() {
115 try { 179 nativeShouldProceed(contentProvider, queryReply, url);
116 nativeShouldProceed(getSupervisedUserContentProvider(), quer yReply, url);
117 } catch (ProcessInitException e) {
118 queryReply.onQueryFailedNoErrorData();
119 }
120 } 180 }
121 }); 181 });
122 try { 182 try {
123 // This will block until an onQueryComplete call on a different thre ad adds 183 // This will block until an onQueryComplete call on a different thre ad adds
124 // something to the queue. 184 // something to the queue.
125 WebRestrictionsResult result = queryReply.getResult(); 185 WebRestrictionsResult result = queryReply.getResult();
126 String histogramName = mChromeAlreadyStarted 186 String histogramName = mChromeAlreadyStarted
127 ? "SupervisedUserContentProvider.ChromeStartedRequestTime" 187 ? "SupervisedUserContentProvider.ChromeStartedRequestTime"
128 : "SupervisedUserContentProvider.ChromeNotStartedRequestTime "; 188 : "SupervisedUserContentProvider.ChromeNotStartedRequestTime ";
129 RecordHistogram.recordTimesHistogram(histogramName, 189 RecordHistogram.recordTimesHistogram(histogramName,
(...skipping 22 matching lines...) Expand all
152 212
153 @Override 213 @Override
154 protected boolean requestInsert(final String url) { 214 protected boolean requestInsert(final String url) {
155 // This will be called on multiple threads (but never the UI thread), 215 // This will be called on multiple threads (but never the UI thread),
156 // see http://developer.android.com/guide/components/processes-and-threa ds.html#ThreadSafe. 216 // see http://developer.android.com/guide/components/processes-and-threa ds.html#ThreadSafe.
157 // The reply comes back on a different thread (possibly the UI thread) s ome time later. 217 // The reply comes back on a different thread (possibly the UI thread) s ome time later.
158 // As such it needs to correctly match the replies to the calls. It does this by creating a 218 // As such it needs to correctly match the replies to the calls. It does this by creating a
159 // reply object for each query, and passing this through the callback st ructure. The reply 219 // reply object for each query, and passing this through the callback st ructure. The reply
160 // object also handles waiting for the reply. 220 // object also handles waiting for the reply.
161 final SupervisedUserInsertReply insertReply = new SupervisedUserInsertRe ply(); 221 final SupervisedUserInsertReply insertReply = new SupervisedUserInsertRe ply();
222 final long contentProvider = getSupervisedUserContentProvider();
223 if (contentProvider == 0) return false;
162 ThreadUtils.runOnUiThread(new Runnable() { 224 ThreadUtils.runOnUiThread(new Runnable() {
163 @Override 225 @Override
164 public void run() { 226 public void run() {
165 try { 227 nativeRequestInsert(contentProvider, insertReply, url);
166 nativeRequestInsert(getSupervisedUserContentProvider(), inse rtReply, url);
167 } catch (ProcessInitException e) {
168 insertReply.onInsertRequestSendComplete(false);
169 }
170 } 228 }
171 }); 229 });
172 try { 230 try {
173 Boolean result = insertReply.getResult(); 231 Boolean result = insertReply.getResult();
174 if (result == null) return false; 232 if (result == null) return false;
175 return result; 233 return result;
176 } catch (InterruptedException e) { 234 } catch (InterruptedException e) {
177 return false; 235 return false;
178 } 236 }
179 } 237 }
180 238
181 @Override
182 public Bundle call(String method, String arg, Bundle bundle) {
183 if (method.equals("setFilterForTesting")) setFilterForTesting();
184 return null;
185 }
186
187 void setFilterForTesting() {
188 ThreadUtils.runOnUiThreadBlocking(new Runnable() {
189 @Override
190 public void run() {
191 try {
192 nativeSetFilterForTesting(getSupervisedUserContentProvider() );
193 } catch (ProcessInitException e) {
194 // There is no way of returning anything sensible here, so i gnore the error and
195 // do nothing.
196 }
197 }
198 });
199 }
200
201 @CalledByNative 239 @CalledByNative
202 void onSupervisedUserFilterUpdated() { 240 void onSupervisedUserFilterUpdated() {
203 onFilterChanged(); 241 onFilterChanged();
204 } 242 }
205 243
206 private static Boolean getEnabled() { 244 private static Boolean getEnabled() {
207 synchronized (sEnabledLock) { 245 synchronized (sEnabledLock) {
208 return sEnabled; 246 return sEnabled;
209 } 247 }
210 } 248 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) 280 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
243 private void updateEnabledState() { 281 private void updateEnabledState() {
244 // This method uses AppRestrictions directly, rather than using the Poli cy interface, 282 // This method uses AppRestrictions directly, rather than using the Poli cy interface,
245 // because it must be callable in contexts in which the native library h asn't been 283 // because it must be callable in contexts in which the native library h asn't been
246 // loaded. It will always be called from a background thread (except pos sibly in tests) 284 // loaded. It will always be called from a background thread (except pos sibly in tests)
247 // so can get the App Restrictions synchronously. 285 // so can get the App Restrictions synchronously.
248 UserManager userManager = (UserManager) getContext().getSystemService(Co ntext.USER_SERVICE); 286 UserManager userManager = (UserManager) getContext().getSystemService(Co ntext.USER_SERVICE);
249 Bundle appRestrictions = userManager 287 Bundle appRestrictions = userManager
250 .getApplicationRestrictions(getContext().getPackageName()); 288 .getApplicationRestrictions(getContext().getPackageName());
251 setEnabled(appRestrictions.getBoolean(SUPERVISED_USER_CONTENT_PROVIDER_E NABLED)); 289 setEnabled(appRestrictions.getBoolean(SUPERVISED_USER_CONTENT_PROVIDER_E NABLED));
252 }; 290 }
291
292 @Override
293 protected String[] getErrorColumnNames() {
294 String result[] = {"Reason", "Allow access requests", "Is child account" ,
295 "Profile image URL", "Second profile image URL", "Custodian", "C ustodian email",
296 "Second custodian", "Second custodian email"};
297 return result;
298 }
299
300 // Helpers for testing.
301
302 @Override
303 public Bundle call(String method, String arg, Bundle bundle) {
304 if (method.equals("setFilterForTesting")) setFilterForTesting();
305 return null;
306 }
307
308 void setFilterForTesting() {
309 final long contentProvider = getSupervisedUserContentProvider();
310 if (contentProvider == 0) return;
311 ThreadUtils.runOnUiThread(new Runnable() {
312 @Override
313 public void run() {
314 nativeSetFilterForTesting(contentProvider);
315 }
316 });
317 }
318
319 void setNativeSupervisedUserContentProviderForTesting(long nativeProvider) {
320 mNativeSupervisedUserContentProvider = nativeProvider;
321 }
253 322
254 @VisibleForTesting 323 @VisibleForTesting
255 public static void enableContentProviderForTesting() { 324 public static void enableContentProviderForTesting() {
256 setEnabled(true); 325 setEnabled(true);
257 } 326 }
258 327
259 native long nativeCreateSupervisedUserContentProvider(); 328 native long nativeCreateSupervisedUserContentProvider();
260 329
261 native void nativeShouldProceed(long nativeSupervisedUserContentProvider, 330 native void nativeShouldProceed(long nativeSupervisedUserContentProvider,
262 SupervisedUserQueryReply queryReply, String url); 331 SupervisedUserQueryReply queryReply, String url);
263 332
264 native void nativeRequestInsert(long nativeSupervisedUserContentProvider, 333 native void nativeRequestInsert(long nativeSupervisedUserContentProvider,
265 SupervisedUserInsertReply insertReply, String url); 334 SupervisedUserInsertReply insertReply, String url);
266 335
267 private native void nativeSetFilterForTesting(long nativeSupervisedUserConte ntProvider); 336 private native void nativeSetFilterForTesting(long nativeSupervisedUserConte ntProvider);
268 337
269 @Override
270 protected String[] getErrorColumnNames() {
271 String result[] = {"Reason", "Allow access requests", "Is child account" ,
272 "Profile image URL", "Second profile image URL", "Custodian", "C ustodian email",
273 "Second custodian", "Second custodian email"};
274 return result;
275 }
276 } 338 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698