Chromium Code Reviews| OLD | NEW |
|---|---|
| 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.customtabs; | 5 package org.chromium.chrome.browser.customtabs; |
| 6 | 6 |
| 7 import android.app.ActivityManager; | 7 import android.app.ActivityManager; |
| 8 import android.app.Application; | 8 import android.app.Application; |
| 9 import android.content.ComponentName; | 9 import android.content.ComponentName; |
| 10 import android.content.Context; | 10 import android.content.Context; |
| 11 import android.content.Intent; | 11 import android.content.Intent; |
| 12 import android.content.ServiceConnection; | 12 import android.content.ServiceConnection; |
| 13 import android.content.pm.PackageManager; | 13 import android.content.pm.PackageManager; |
| 14 import android.content.res.Resources; | 14 import android.content.res.Resources; |
| 15 import android.graphics.Point; | 15 import android.graphics.Point; |
| 16 import android.net.ConnectivityManager; | 16 import android.net.ConnectivityManager; |
| 17 import android.net.Uri; | 17 import android.net.Uri; |
| 18 import android.os.AsyncTask; | 18 import android.os.AsyncTask; |
| 19 import android.os.Binder; | 19 import android.os.Binder; |
| 20 import android.os.Build; | 20 import android.os.Build; |
| 21 import android.os.Bundle; | 21 import android.os.Bundle; |
| 22 import android.os.IBinder; | 22 import android.os.IBinder; |
| 23 import android.os.Process; | 23 import android.os.Process; |
| 24 import android.os.RemoteException; | 24 import android.os.RemoteException; |
| 25 import android.os.SystemClock; | 25 import android.os.SystemClock; |
| 26 import android.support.customtabs.ICustomTabsCallback; | 26 import android.support.customtabs.ICustomTabsCallback; |
| 27 import android.support.customtabs.ICustomTabsService; | 27 import android.support.customtabs.ICustomTabsService; |
| 28 import android.text.TextUtils; | 28 import android.text.TextUtils; |
| 29 import android.util.SparseArray; | 29 import android.util.SparseArray; |
| 30 import android.util.SparseBooleanArray; | |
| 30 import android.view.WindowManager; | 31 import android.view.WindowManager; |
| 31 | 32 |
| 32 import org.chromium.base.FieldTrialList; | 33 import org.chromium.base.FieldTrialList; |
| 33 import org.chromium.base.Log; | 34 import org.chromium.base.Log; |
| 34 import org.chromium.base.ThreadUtils; | 35 import org.chromium.base.ThreadUtils; |
| 35 import org.chromium.base.VisibleForTesting; | 36 import org.chromium.base.VisibleForTesting; |
| 36 import org.chromium.base.annotations.SuppressFBWarnings; | 37 import org.chromium.base.annotations.SuppressFBWarnings; |
| 37 import org.chromium.base.library_loader.ProcessInitException; | 38 import org.chromium.base.library_loader.ProcessInitException; |
| 38 import org.chromium.base.metrics.RecordHistogram; | 39 import org.chromium.base.metrics.RecordHistogram; |
| 39 import org.chromium.chrome.R; | 40 import org.chromium.chrome.R; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 72 private static final String TAG = "cr.ChromeConnection"; | 73 private static final String TAG = "cr.ChromeConnection"; |
| 73 @VisibleForTesting | 74 @VisibleForTesting |
| 74 static final String NO_PRERENDERING_KEY = | 75 static final String NO_PRERENDERING_KEY = |
| 75 "android.support.customtabs.maylaunchurl.NO_PRERENDERING"; | 76 "android.support.customtabs.maylaunchurl.NO_PRERENDERING"; |
| 76 | 77 |
| 77 // Values for the "CustomTabs.PredictionStatus" UMA histogram. Append-only. | 78 // Values for the "CustomTabs.PredictionStatus" UMA histogram. Append-only. |
| 78 private static final int NO_PREDICTION = 0; | 79 private static final int NO_PREDICTION = 0; |
| 79 private static final int GOOD_PREDICTION = 1; | 80 private static final int GOOD_PREDICTION = 1; |
| 80 private static final int BAD_PREDICTION = 2; | 81 private static final int BAD_PREDICTION = 2; |
| 81 private static final int PREDICTION_STATUS_COUNT = 3; | 82 private static final int PREDICTION_STATUS_COUNT = 3; |
| 83 // Values for the "CustomTabs.CalledWarmup" UMA histogram. Append-only. | |
|
pasko
2015/09/03 18:02:19
nittynit: empty line above would look nicer
Benoit L
2015/09/29 09:04:23
Ack.
| |
| 84 private static final int NO_SESSION_NO_WARMUP = 0; | |
| 85 private static final int NO_SESSION_WARMUP = 1; | |
| 86 private static final int SESSION_NO_WARMUP_ALREADY_CALLED = 2; | |
| 87 private static final int SESSION_NO_WARMUP_NOT_CALLED = 3; | |
| 88 private static final int SESSION_WARMUP = 4; | |
| 89 private static final int SESSION_WARMUP_COUNT = 5; | |
| 82 | 90 |
| 83 private static AtomicReference<CustomTabsConnection> sInstance = | 91 private static AtomicReference<CustomTabsConnection> sInstance = |
| 84 new AtomicReference<CustomTabsConnection>(); | 92 new AtomicReference<CustomTabsConnection>(); |
| 85 | 93 |
| 86 private static final class PrerenderedUrlParams { | 94 private static final class PrerenderedUrlParams { |
| 87 public final IBinder mSession; | 95 public final IBinder mSession; |
| 88 public final WebContents mWebContents; | 96 public final WebContents mWebContents; |
| 89 public final String mUrl; | 97 public final String mUrl; |
| 90 public final String mReferrer; | 98 public final String mReferrer; |
| 91 public final Bundle mExtras; | 99 public final Bundle mExtras; |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 184 | 192 |
| 185 public String getPredictedUrl() { | 193 public String getPredictedUrl() { |
| 186 return mPredictedUrl; | 194 return mPredictedUrl; |
| 187 } | 195 } |
| 188 | 196 |
| 189 public long getLastMayLaunchUrlTimestamp() { | 197 public long getLastMayLaunchUrlTimestamp() { |
| 190 return mLastMayLaunchUrlTimestamp; | 198 return mLastMayLaunchUrlTimestamp; |
| 191 } | 199 } |
| 192 } | 200 } |
| 193 | 201 |
| 194 private final Object mLock = new Object(); | 202 private final Object mLock = new Object(); |
|
pasko
2015/09/03 18:02:20
please add a comment saying something like: 'mLock
Benoit L
2015/09/29 09:04:23
Refactored this, so... done?
| |
| 195 private final Map<IBinder, SessionParams> mSessionParams = new HashMap<>(); | 203 private final Map<IBinder, SessionParams> mSessionParams = new HashMap<>(); |
| 196 // Prediction tracking is done by UID and not by session, since a | 204 // Prediction tracking is done by UID and not by session, since a |
| 197 // mis-behaving application can create a large number of sessions. | 205 // mis-behaving application can create a large number of sessions. |
| 198 private SparseArray<PredictionStats> mUidToPredictionsStats = new SparseArra y<>(); | 206 private SparseArray<PredictionStats> mUidToPredictionsStats = new SparseArra y<>(); |
| 207 // Whether a client application has called warmup() in this instance lifetim e. | |
| 208 private SparseBooleanArray mUidHasCalledWarmup = new SparseBooleanArray(); | |
| 199 | 209 |
| 200 /** | 210 /** |
| 201 * <strong>DO NOT CALL</strong> | 211 * <strong>DO NOT CALL</strong> |
| 202 * Public to be instanciable from {@link ChromeApplication}. This is however | 212 * Public to be instanciable from {@link ChromeApplication}. This is however |
| 203 * intended to be private. | 213 * intended to be private. |
| 204 */ | 214 */ |
| 205 public CustomTabsConnection(Application application) { | 215 public CustomTabsConnection(Application application) { |
| 206 super(); | 216 super(); |
| 207 mApplication = application; | 217 mApplication = application; |
| 208 } | 218 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 254 mUidToPredictionsStats.put(uid, new PredictionStats()); | 264 mUidToPredictionsStats.put(uid, new PredictionStats()); |
| 255 } | 265 } |
| 256 } | 266 } |
| 257 return true; | 267 return true; |
| 258 } | 268 } |
| 259 | 269 |
| 260 @Override | 270 @Override |
| 261 public boolean warmup(long flags) { | 271 public boolean warmup(long flags) { |
| 262 // Here and in mayLaunchUrl(), don't do expensive work for background ap plications. | 272 // Here and in mayLaunchUrl(), don't do expensive work for background ap plications. |
| 263 if (!isCallerForegroundOrSelf()) return false; | 273 if (!isCallerForegroundOrSelf()) return false; |
| 274 | |
| 275 synchronized (mLock) { | |
| 276 mUidHasCalledWarmup.put(Binder.getCallingUid(), true); | |
| 277 } | |
| 278 | |
| 264 if (!mWarmupHasBeenCalled.compareAndSet(false, true)) return true; | 279 if (!mWarmupHasBeenCalled.compareAndSet(false, true)) return true; |
| 265 // The call is non-blocking and this must execute on the UI thread, post a task. | 280 // The call is non-blocking and this must execute on the UI thread, post a task. |
| 266 ThreadUtils.postOnUiThread(new Runnable() { | 281 ThreadUtils.postOnUiThread(new Runnable() { |
| 267 @Override | 282 @Override |
| 268 @SuppressFBWarnings("DM_EXIT") | 283 @SuppressFBWarnings("DM_EXIT") |
| 269 public void run() { | 284 public void run() { |
| 270 ChromeApplication app = (ChromeApplication) mApplication; | 285 ChromeApplication app = (ChromeApplication) mApplication; |
| 271 try { | 286 try { |
| 272 app.startBrowserProcessesAndLoadLibrariesSync(true); | 287 app.startBrowserProcessesAndLoadLibrariesSync(true); |
| 273 } catch (ProcessInitException e) { | 288 } catch (ProcessInitException e) { |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 377 } | 392 } |
| 378 | 393 |
| 379 /** | 394 /** |
| 380 * Registers a launch of a |url| for a given |session|. | 395 * Registers a launch of a |url| for a given |session|. |
| 381 * | 396 * |
| 382 * This is used for accounting. | 397 * This is used for accounting. |
| 383 */ | 398 */ |
| 384 void registerLaunch(IBinder session, String url) { | 399 void registerLaunch(IBinder session, String url) { |
| 385 int outcome; | 400 int outcome; |
| 386 long elapsedTimeMs = -1; | 401 long elapsedTimeMs = -1; |
| 402 boolean hasValidSession = false; | |
| 403 boolean hasUidCalledWarmup = false; | |
| 387 synchronized (mLock) { | 404 synchronized (mLock) { |
| 388 SessionParams sessionParams = mSessionParams.get(session); | 405 SessionParams sessionParams = mSessionParams.get(session); |
| 389 if (sessionParams == null) { | 406 if (sessionParams == null) { |
| 390 outcome = NO_PREDICTION; | 407 outcome = NO_PREDICTION; |
| 391 } else { | 408 } else { |
| 409 hasValidSession = true; | |
| 410 hasUidCalledWarmup = mUidHasCalledWarmup.get(sessionParams.mUid) ; | |
| 411 | |
| 392 String predictedUrl = sessionParams.getPredictedUrl(); | 412 String predictedUrl = sessionParams.getPredictedUrl(); |
| 393 outcome = predictedUrl == null ? NO_PREDICTION | 413 outcome = predictedUrl == null ? NO_PREDICTION |
| 394 : predictedUrl.equals(url) ? GOOD_PREDICTION : BAD_PREDI CTION; | 414 : predictedUrl.equals(url) ? GOOD_PREDICTION : BAD_PREDI CTION; |
| 395 elapsedTimeMs = SystemClock.elapsedRealtime() | 415 elapsedTimeMs = SystemClock.elapsedRealtime() |
| 396 - sessionParams.getLastMayLaunchUrlTimestamp(); | 416 - sessionParams.getLastMayLaunchUrlTimestamp(); |
| 397 sessionParams.setPredictionMetrics(null, 0); | 417 sessionParams.setPredictionMetrics(null, 0); |
| 398 if (outcome == GOOD_PREDICTION) { | 418 if (outcome == GOOD_PREDICTION) { |
| 399 // If the prediction was correct, back to the smallest | 419 // If the prediction was correct, back to the smallest |
| 400 // throttling level. | 420 // throttling level. |
| 401 mUidToPredictionsStats.put(sessionParams.mUid, new Predictio nStats()); | 421 mUidToPredictionsStats.put(sessionParams.mUid, new Predictio nStats()); |
| 402 } | 422 } |
| 403 } | 423 } |
| 404 } | 424 } |
| 405 RecordHistogram.recordEnumeratedHistogram( | 425 RecordHistogram.recordEnumeratedHistogram( |
| 406 "CustomTabs.PredictionStatus", outcome, PREDICTION_STATUS_COUNT) ; | 426 "CustomTabs.PredictionStatus", outcome, PREDICTION_STATUS_COUNT) ; |
| 407 if (outcome == GOOD_PREDICTION) { | 427 if (outcome == GOOD_PREDICTION) { |
| 408 RecordHistogram.recordCustomTimesHistogram("CustomTabs.PredictionToL aunch", | 428 RecordHistogram.recordCustomTimesHistogram("CustomTabs.PredictionToL aunch", |
| 409 elapsedTimeMs, 1, TimeUnit.MINUTES.toMillis(3), TimeUnit.MIL LISECONDS, 100); | 429 elapsedTimeMs, 1, TimeUnit.MINUTES.toMillis(3), TimeUnit.MIL LISECONDS, 100); |
| 410 } | 430 } |
| 431 // CustomTabs.CalledWarmup histogram. | |
| 432 boolean warmupCalled = mWarmupHasBeenCalled.get(); | |
| 433 int warmupKind = warmupCalled ? NO_SESSION_WARMUP : NO_SESSION_NO_WARMUP ; | |
| 434 if (hasValidSession) { | |
| 435 if (hasUidCalledWarmup) { | |
| 436 warmupKind = SESSION_WARMUP; | |
| 437 } else { | |
| 438 warmupKind = warmupCalled ? SESSION_NO_WARMUP_ALREADY_CALLED | |
| 439 : SESSION_NO_WARMUP_NOT_CALLED; | |
| 440 } | |
| 441 } | |
| 442 RecordHistogram.recordEnumeratedHistogram( | |
| 443 "CustomTabs.CalledWarmup", warmupKind, SESSION_WARMUP_COUNT); | |
| 411 } | 444 } |
| 412 | 445 |
| 413 /** | 446 /** |
| 414 * Transfers a prerendered WebContents if one exists. | 447 * Transfers a prerendered WebContents if one exists. |
| 415 * | 448 * |
| 416 * This resets the internal WebContents; a subsequent call to this method | 449 * This resets the internal WebContents; a subsequent call to this method |
| 417 * returns null. Must be called from the UI thread. | 450 * returns null. Must be called from the UI thread. |
| 418 * If a prerender exists for a different URL with the same sessionId or with | 451 * If a prerender exists for a different URL with the same sessionId or with |
| 419 * a different referrer, then this is treated as a mispredict from the | 452 * a different referrer, then this is treated as a mispredict from the |
| 420 * client application, and cancels the previous prerender. This is done to | 453 * client application, and cancels the previous prerender. This is done to |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 630 } | 663 } |
| 631 | 664 |
| 632 /** | 665 /** |
| 633 * Called when a remote client has died. | 666 * Called when a remote client has died. |
| 634 */ | 667 */ |
| 635 private void cleanupAlreadyLocked(IBinder session) { | 668 private void cleanupAlreadyLocked(IBinder session) { |
| 636 ThreadUtils.assertOnUiThread(); | 669 ThreadUtils.assertOnUiThread(); |
| 637 SessionParams params = mSessionParams.get(session); | 670 SessionParams params = mSessionParams.get(session); |
| 638 if (params == null) return; | 671 if (params == null) return; |
| 639 mSessionParams.remove(session); | 672 mSessionParams.remove(session); |
| 673 mUidHasCalledWarmup.delete(params.mUid); | |
| 640 IBinder binder = params.mCallback.asBinder(); | 674 IBinder binder = params.mCallback.asBinder(); |
| 641 binder.unlinkToDeath(params.mDeathRecipient, 0); | 675 binder.unlinkToDeath(params.mDeathRecipient, 0); |
| 642 if (mPrerender != null && session.equals(mPrerender.mSession)) { | 676 if (mPrerender != null && session.equals(mPrerender.mSession)) { |
| 643 prerenderUrl(session, null, null); // Cancels the pre-render. | 677 prerenderUrl(session, null, null); // Cancels the pre-render. |
| 644 } | 678 } |
| 645 } | 679 } |
| 646 | 680 |
| 647 private boolean mayPrerender() { | 681 private boolean mayPrerender() { |
| 648 if (FieldTrialList.findFullName("CustomTabs").equals("DisablePrerender") ) return false; | 682 if (FieldTrialList.findFullName("CustomTabs").equals("DisablePrerender") ) return false; |
| 649 if (!DeviceClassManager.enablePrerendering()) return false; | 683 if (!DeviceClassManager.enablePrerendering()) return false; |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 717 return screenSize; | 751 return screenSize; |
| 718 } | 752 } |
| 719 | 753 |
| 720 @VisibleForTesting | 754 @VisibleForTesting |
| 721 void resetThrottling(int uid) { | 755 void resetThrottling(int uid) { |
| 722 synchronized (mLock) { | 756 synchronized (mLock) { |
| 723 mUidToPredictionsStats.put(uid, new PredictionStats()); | 757 mUidToPredictionsStats.put(uid, new PredictionStats()); |
| 724 } | 758 } |
| 725 } | 759 } |
| 726 } | 760 } |
| OLD | NEW |