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

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: 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.ThreadUtils; 17 import org.chromium.base.ThreadUtils;
18 import org.chromium.base.VisibleForTesting; 18 import org.chromium.base.VisibleForTesting;
19 import org.chromium.base.annotations.CalledByNative; 19 import org.chromium.base.annotations.CalledByNative;
20 import org.chromium.base.library_loader.LibraryLoader; 20 import org.chromium.base.library_loader.LibraryLoader;
21 import org.chromium.base.library_loader.ProcessInitException; 21 import org.chromium.base.library_loader.ProcessInitException;
22 import org.chromium.base.metrics.RecordHistogram; 22 import org.chromium.base.metrics.RecordHistogram;
23 import org.chromium.chrome.browser.childaccounts.ChildAccountService;
24 import org.chromium.chrome.browser.firstrun.ForcedSigninProcessor;
23 import org.chromium.chrome.browser.init.ChromeBrowserInitializer; 25 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
26 import org.chromium.components.signin.ChromeSigninController;
24 import org.chromium.components.webrestrictions.browser.WebRestrictionsContentPro vider; 27 import org.chromium.components.webrestrictions.browser.WebRestrictionsContentPro vider;
25 28
26 import java.util.concurrent.ArrayBlockingQueue; 29 import java.util.concurrent.ArrayBlockingQueue;
27 import java.util.concurrent.BlockingQueue; 30 import java.util.concurrent.BlockingQueue;
28 import java.util.concurrent.TimeUnit; 31 import java.util.concurrent.TimeUnit;
29 32
30 /** 33 /**
31 * Content provider for telling other apps (e.g. WebView apps) about the supervi sed user URL filter. 34 * Content provider for telling other apps (e.g. WebView apps) about the supervi sed user URL filter.
32 */ 35 */
33 public class SupervisedUserContentProvider extends WebRestrictionsContentProvide r { 36 public class SupervisedUserContentProvider extends WebRestrictionsContentProvide r {
34 private static final String SUPERVISED_USER_CONTENT_PROVIDER_ENABLED = 37 private static final String SUPERVISED_USER_CONTENT_PROVIDER_ENABLED =
35 "SupervisedUserContentProviderEnabled"; 38 "SupervisedUserContentProviderEnabled";
36 private long mNativeSupervisedUserContentProvider; 39 private long mNativeSupervisedUserContentProvider;
37 private boolean mChromeAlreadyStarted; 40 private boolean mChromeAlreadyStarted;
38 private static Object sEnabledLock = new Object(); 41 private static Object sEnabledLock = new Object();
42 private static Object sContentProviderLock = new Object();
43
44 // Must match the value in supervised_user_error_page.h
45 private static final int NOT_SIGNED_IN = 5;
46
47 private static final String TAG = "SupervisedUserContent";
39 48
40 // Three value "boolean" caching enabled state, null if not yet known. 49 // Three value "boolean" caching enabled state, null if not yet known.
41 private static Boolean sEnabled; 50 private static Boolean sEnabled;
42 51
43 private long getSupervisedUserContentProvider() throws ProcessInitException { 52 @VisibleForTesting
44 mChromeAlreadyStarted = LibraryLoader.isInitialized(); 53 void startForcedSigninProcessor(Context appContext, Runnable onComplete) {
45 if (mNativeSupervisedUserContentProvider != 0) { 54 ForcedSigninProcessor.start(appContext, onComplete);
46 return mNativeSupervisedUserContentProvider;
47 }
48
49 ChromeBrowserInitializer.getInstance(getContext()).handleSynchronousStar tup();
50
51 mNativeSupervisedUserContentProvider = nativeCreateSupervisedUserContent Provider();
52 return mNativeSupervisedUserContentProvider;
53 } 55 }
54 56
55 void setNativeSupervisedUserContentProviderForTesting(long nativeProvider) { 57 @VisibleForTesting
56 mNativeSupervisedUserContentProvider = nativeProvider; 58 void listenForChildAccountStatusChange(Runnable callback) {
59 ChildAccountService.listenForStatusChange(callback);
60 }
61
62 private long getSupervisedUserContentProvider() {
63 synchronized (sContentProviderLock) {
Bernhard Bauer 2017/02/15 15:09:37 Maybe add a comment that this potentially holds th
aberent 2017/02/15 18:34:46 Done.
64 mChromeAlreadyStarted = LibraryLoader.isInitialized();
65 if (mNativeSupervisedUserContentProvider != 0) {
66 return mNativeSupervisedUserContentProvider;
67 }
68 final Context appContext = getContext().getApplicationContext();
69 final SupervisedUserReply<Long> reply = new SupervisedUserReply<>();
70 ThreadUtils.runOnUiThread(new Runnable() {
71 @Override
72 public void run() {
73 try {
74 ChromeBrowserInitializer.getInstance(appContext).handleS ynchronousStartup();
75 } catch (ProcessInitException e) {
76 reply.onQueryFinished(0L);
77 return;
78 }
79 final ChromeSigninController chromeSigninController =
80 ChromeSigninController.get(appContext);
81 if (chromeSigninController.isSignedIn()) {
82 reply.onQueryFinished(nativeCreateSupervisedUserContentP rovider());
83 return;
84 }
85 // Try to sign in, Chrome needs to be signed in to get the U RL filter.
86 startForcedSigninProcessor(appContext, new Runnable() {
87 @Override
88 public void run() {
89 if (!chromeSigninController.isSignedIn()) {
90 reply.onQueryFinished(0L);
91 return;
92 }
93 // Wait for the status change; Chrome can't check an y URLs until this
94 // has happened.
95 listenForChildAccountStatusChange(new Runnable() {
96 @Override
97 public void run() {
98 reply.onQueryFinished(
99 nativeCreateSupervisedUserContentPro vider());
100 }
101 });
102 }
103 });
104 }
105 });
106 try {
107 mNativeSupervisedUserContentProvider = reply.getResult();
108 return mNativeSupervisedUserContentProvider;
109 } catch (InterruptedException e) {
110 return 0;
111 }
112 }
57 } 113 }
58 114
59 static class SupervisedUserReply<T> { 115 static class SupervisedUserReply<T> {
60 private static final long RESULT_TIMEOUT_SECONDS = 10; 116 private static final long RESULT_TIMEOUT_SECONDS = 10;
61 final BlockingQueue<T> mQueue = new ArrayBlockingQueue<>(1); 117 final BlockingQueue<T> mQueue = new ArrayBlockingQueue<>(1);
62 118
63 void onQueryFinished(T reply) { 119 void onQueryFinished(T reply) {
64 // This must be called precisely once per query. 120 // This must be called precisely once per query.
65 mQueue.add(reply); 121 mQueue.add(reply);
66 } 122 }
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 @Override 158 @Override
103 protected WebRestrictionsResult shouldProceed(final String url) { 159 protected WebRestrictionsResult shouldProceed(final String url) {
104 // This will be called on multiple threads (but never the UI thread), 160 // 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. 161 // 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. 162 // 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 163 // 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 164 // reply object for each query, and passing this through the callback st ructure. The reply
109 // object also handles waiting for the reply. 165 // object also handles waiting for the reply.
110 long startTimeMs = SystemClock.elapsedRealtime(); 166 long startTimeMs = SystemClock.elapsedRealtime();
111 final SupervisedUserQueryReply queryReply = new SupervisedUserQueryReply (); 167 final SupervisedUserQueryReply queryReply = new SupervisedUserQueryReply ();
168 final long contentProvider = getSupervisedUserContentProvider();
169 if (contentProvider == 0) {
170 return new WebRestrictionsResult(false, new int[] {NOT_SIGNED_IN}, n ull);
171 }
112 ThreadUtils.runOnUiThread(new Runnable() { 172 ThreadUtils.runOnUiThread(new Runnable() {
113 @Override 173 @Override
114 public void run() { 174 public void run() {
115 try { 175 nativeShouldProceed(contentProvider, queryReply, url);
116 nativeShouldProceed(getSupervisedUserContentProvider(), quer yReply, url);
117 } catch (ProcessInitException e) {
118 queryReply.onQueryFailedNoErrorData();
119 }
120 } 176 }
121 }); 177 });
122 try { 178 try {
123 // This will block until an onQueryComplete call on a different thre ad adds 179 // This will block until an onQueryComplete call on a different thre ad adds
124 // something to the queue. 180 // something to the queue.
125 WebRestrictionsResult result = queryReply.getResult(); 181 WebRestrictionsResult result = queryReply.getResult();
126 String histogramName = mChromeAlreadyStarted 182 String histogramName = mChromeAlreadyStarted
127 ? "SupervisedUserContentProvider.ChromeStartedRequestTime" 183 ? "SupervisedUserContentProvider.ChromeStartedRequestTime"
128 : "SupervisedUserContentProvider.ChromeNotStartedRequestTime "; 184 : "SupervisedUserContentProvider.ChromeNotStartedRequestTime ";
129 RecordHistogram.recordTimesHistogram(histogramName, 185 RecordHistogram.recordTimesHistogram(histogramName,
(...skipping 22 matching lines...) Expand all
152 208
153 @Override 209 @Override
154 protected boolean requestInsert(final String url) { 210 protected boolean requestInsert(final String url) {
155 // This will be called on multiple threads (but never the UI thread), 211 // 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. 212 // 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. 213 // 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 214 // 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 215 // reply object for each query, and passing this through the callback st ructure. The reply
160 // object also handles waiting for the reply. 216 // object also handles waiting for the reply.
161 final SupervisedUserInsertReply insertReply = new SupervisedUserInsertRe ply(); 217 final SupervisedUserInsertReply insertReply = new SupervisedUserInsertRe ply();
218 final long contentProvider = getSupervisedUserContentProvider();
219 if (contentProvider == 0) return false;
162 ThreadUtils.runOnUiThread(new Runnable() { 220 ThreadUtils.runOnUiThread(new Runnable() {
163 @Override 221 @Override
164 public void run() { 222 public void run() {
165 try { 223 nativeRequestInsert(contentProvider, insertReply, url);
166 nativeRequestInsert(getSupervisedUserContentProvider(), inse rtReply, url);
167 } catch (ProcessInitException e) {
168 insertReply.onInsertRequestSendComplete(false);
169 }
170 } 224 }
171 }); 225 });
172 try { 226 try {
173 Boolean result = insertReply.getResult(); 227 Boolean result = insertReply.getResult();
174 if (result == null) return false; 228 if (result == null) return false;
175 return result; 229 return result;
176 } catch (InterruptedException e) { 230 } catch (InterruptedException e) {
177 return false; 231 return false;
178 } 232 }
179 } 233 }
180 234
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 235 @CalledByNative
202 void onSupervisedUserFilterUpdated() { 236 void onSupervisedUserFilterUpdated() {
203 onFilterChanged(); 237 onFilterChanged();
204 } 238 }
205 239
206 private static Boolean getEnabled() { 240 private static Boolean getEnabled() {
207 synchronized (sEnabledLock) { 241 synchronized (sEnabledLock) {
208 return sEnabled; 242 return sEnabled;
209 } 243 }
210 } 244 }
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) 276 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
243 private void updateEnabledState() { 277 private void updateEnabledState() {
244 // This method uses AppRestrictions directly, rather than using the Poli cy interface, 278 // 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 279 // 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) 280 // loaded. It will always be called from a background thread (except pos sibly in tests)
247 // so can get the App Restrictions synchronously. 281 // so can get the App Restrictions synchronously.
248 UserManager userManager = (UserManager) getContext().getSystemService(Co ntext.USER_SERVICE); 282 UserManager userManager = (UserManager) getContext().getSystemService(Co ntext.USER_SERVICE);
249 Bundle appRestrictions = userManager 283 Bundle appRestrictions = userManager
250 .getApplicationRestrictions(getContext().getPackageName()); 284 .getApplicationRestrictions(getContext().getPackageName());
251 setEnabled(appRestrictions.getBoolean(SUPERVISED_USER_CONTENT_PROVIDER_E NABLED)); 285 setEnabled(appRestrictions.getBoolean(SUPERVISED_USER_CONTENT_PROVIDER_E NABLED));
252 }; 286 }
287
288 @Override
289 protected String[] getErrorColumnNames() {
290 String result[] = {"Reason", "Allow access requests", "Is child account" ,
291 "Profile image URL", "Second profile image URL", "Custodian", "C ustodian email",
292 "Second custodian", "Second custodian email"};
293 return result;
294 }
295
296 // Helpers for testing.
297
298 @Override
299 public Bundle call(String method, String arg, Bundle bundle) {
300 if (method.equals("setFilterForTesting")) setFilterForTesting();
301 return null;
302 }
303
304 void setFilterForTesting() {
305 final long contentProvider = getSupervisedUserContentProvider();
306 if (contentProvider == 0) return;
307 ThreadUtils.runOnUiThread(new Runnable() {
308 @Override
309 public void run() {
310 nativeSetFilterForTesting(contentProvider);
311 }
312 });
313 }
314
315 void setNativeSupervisedUserContentProviderForTesting(long nativeProvider) {
316 mNativeSupervisedUserContentProvider = nativeProvider;
317 }
253 318
254 @VisibleForTesting 319 @VisibleForTesting
255 public static void enableContentProviderForTesting() { 320 public static void enableContentProviderForTesting() {
256 setEnabled(true); 321 setEnabled(true);
257 } 322 }
258 323
259 native long nativeCreateSupervisedUserContentProvider(); 324 native long nativeCreateSupervisedUserContentProvider();
260 325
261 native void nativeShouldProceed(long nativeSupervisedUserContentProvider, 326 native void nativeShouldProceed(long nativeSupervisedUserContentProvider,
262 SupervisedUserQueryReply queryReply, String url); 327 SupervisedUserQueryReply queryReply, String url);
263 328
264 native void nativeRequestInsert(long nativeSupervisedUserContentProvider, 329 native void nativeRequestInsert(long nativeSupervisedUserContentProvider,
265 SupervisedUserInsertReply insertReply, String url); 330 SupervisedUserInsertReply insertReply, String url);
266 331
267 private native void nativeSetFilterForTesting(long nativeSupervisedUserConte ntProvider); 332 private native void nativeSetFilterForTesting(long nativeSupervisedUserConte ntProvider);
268 333
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 } 334 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698