Chromium Code Reviews| Index: chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/ChromeBrowserConnection.java |
| diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/ChromeBrowserConnection.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/ChromeBrowserConnection.java |
| index 363c99f412b4e13c16a1f8dc62272eb1139ee3e3..8545ec872150dcadb37129ca3a88bf272f783493 100644 |
| --- a/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/ChromeBrowserConnection.java |
| +++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/ChromeBrowserConnection.java |
| @@ -17,6 +17,7 @@ import android.os.Binder; |
| import android.os.Bundle; |
| import android.os.IBinder; |
| import android.os.RemoteException; |
| +import android.os.SystemClock; |
| import android.util.LongSparseArray; |
| import android.util.SparseArray; |
| @@ -24,6 +25,7 @@ import org.chromium.base.Log; |
| import org.chromium.base.ThreadUtils; |
| import org.chromium.base.annotations.SuppressFBWarnings; |
| import org.chromium.base.library_loader.ProcessInitException; |
| +import org.chromium.base.metrics.RecordHistogram; |
| import org.chromium.chrome.browser.ChromiumApplication; |
| import org.chromium.chrome.browser.WarmupManager; |
| import org.chromium.content.browser.ChildProcessLauncher; |
| @@ -33,6 +35,7 @@ import java.security.SecureRandom; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| +import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| /** |
| @@ -42,6 +45,9 @@ class ChromeBrowserConnection extends IBrowserConnectionService.Stub { |
| private static final String TAG = Log.makeTag("ChromeConnection"); |
| private static final long RESULT_OK = 0; |
| private static final long RESULT_ERROR = -1; |
| + private static final int NO_PREDICTION = 0; |
| + private static final int GOOD_PREDICTION = 1; |
| + private static final int BAD_PREDICTION = 2; |
| private static final Object sConstructionLock = new Object(); |
| private static ChromeBrowserConnection sInstance; |
| @@ -49,10 +55,45 @@ class ChromeBrowserConnection extends IBrowserConnectionService.Stub { |
| private final Application mApplication; |
| private final AtomicBoolean mWarmupHasBeenCalled; |
| + /** Per-sessionId values. */ |
| + private static class SessionParams { |
| + public final int mUid; |
| + private ServiceConnection mServiceConnection; |
| + private String mPredictedUrl; |
| + private long mLastMayLaunchUrlTimestamp; |
| + |
| + public SessionParams(int uid) { |
| + mUid = uid; |
| + mServiceConnection = null; |
| + mPredictedUrl = null; |
| + mLastMayLaunchUrlTimestamp = 0; |
| + } |
| + |
| + public ServiceConnection getServiceConnection() { |
| + return mServiceConnection; |
| + } |
| + |
| + public void setServiceConnection(ServiceConnection serviceConnection) { |
| + mServiceConnection = serviceConnection; |
| + } |
| + |
| + public void setPredictionMetrics(String predictedUrl, long lastMayLaunchUrlTimestamp) { |
| + mPredictedUrl = predictedUrl; |
| + mLastMayLaunchUrlTimestamp = lastMayLaunchUrlTimestamp; |
| + } |
| + |
| + public String getPredictedUrl() { |
| + return mPredictedUrl; |
| + } |
| + |
| + public long getLastMayLaunchUrlTimestamp() { |
| + return mLastMayLaunchUrlTimestamp; |
| + } |
| + } |
| + |
| private final Object mLock; |
| private final SparseArray<IBrowserConnectionCallback> mUidToCallback; |
| - private final LongSparseArray<Integer> mSessionIdToUid; |
| - private final LongSparseArray<ServiceConnection> mSessionIdToServiceConnection; |
| + private final LongSparseArray<SessionParams> mSessionParams; |
| private ChromeBrowserConnection(Application application) { |
| super(); |
| @@ -60,8 +101,7 @@ class ChromeBrowserConnection extends IBrowserConnectionService.Stub { |
| mWarmupHasBeenCalled = new AtomicBoolean(); |
| mLock = new Object(); |
| mUidToCallback = new SparseArray<IBrowserConnectionCallback>(); |
| - mSessionIdToUid = new LongSparseArray<Integer>(); |
| - mSessionIdToServiceConnection = new LongSparseArray<ServiceConnection>(); |
| + mSessionParams = new LongSparseArray<SessionParams>(); |
| } |
| /** |
| @@ -143,8 +183,8 @@ class ChromeBrowserConnection extends IBrowserConnectionService.Stub { |
| // Because Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE. |
| if (sessionId == Long.MIN_VALUE) continue; |
| sessionId = Math.abs(sessionId); |
| - } while (sessionId == 0 || mSessionIdToUid.get(sessionId) != null); |
| - mSessionIdToUid.put(sessionId, Binder.getCallingUid()); |
| + } while (sessionId == 0 || mSessionParams.get(sessionId) != null); |
| + mSessionParams.put(sessionId, new SessionParams(Binder.getCallingUid())); |
| return sessionId; |
| } |
| } |
| @@ -155,9 +195,9 @@ class ChromeBrowserConnection extends IBrowserConnectionService.Stub { |
| int uid = Binder.getCallingUid(); |
| if (!isUidForeground(uid)) return RESULT_ERROR; |
| synchronized (mLock) { |
| - if (mSessionIdToUid.get(sessionId) == null || mSessionIdToUid.get(sessionId) != uid) { |
| - return RESULT_ERROR; |
| - } |
| + SessionParams sessionParams = mSessionParams.get(sessionId); |
| + if (sessionParams == null || sessionParams.mUid != uid) return RESULT_ERROR; |
| + sessionParams.setPredictionMetrics(url, SystemClock.elapsedRealtime()); |
| } |
| ThreadUtils.postOnUiThread(new Runnable() { |
| @Override |
| @@ -171,6 +211,35 @@ class ChromeBrowserConnection extends IBrowserConnectionService.Stub { |
| } |
| /** |
| + * Registers a launch of a |url| for a given |sessionId|. |
| + * |
| + * This is used for accounting. |
| + */ |
| + void registerLaunch(long sessionId, String url) { |
| + int outcome; |
| + long elapsedTimeMs = -1; |
| + synchronized (mLock) { |
| + SessionParams sessionParams = mSessionParams.get(sessionId); |
| + if (sessionParams == null) { |
| + outcome = NO_PREDICTION; |
| + } else { |
| + String predictedUrl = sessionParams.getPredictedUrl(); |
| + outcome = predictedUrl == null ? NO_PREDICTION |
| + : predictedUrl.equals(url) ? GOOD_PREDICTION : BAD_PREDICTION; |
| + elapsedTimeMs = SystemClock.elapsedRealtime() |
| + - sessionParams.getLastMayLaunchUrlTimestamp(); |
| + sessionParams.setPredictionMetrics(null, 0); |
| + } |
| + } |
| + RecordHistogram.recordEnumeratedHistogram( |
| + "CustomTabs.PredictionStatus", outcome, BAD_PREDICTION + 1); |
|
Ilya Sherman
2015/06/03 22:07:32
Using "BAD_PREDICTION + 1" as the bound is fragile
Benoit L
2015/06/04 11:16:29
You're right, added the boundary value and the com
|
| + if (outcome == GOOD_PREDICTION) { |
| + RecordHistogram.recordCustomTimesHistogram("CustomTabs.PredictionToLaunch", |
| + elapsedTimeMs, 0, 3 * 60 * 1000, TimeUnit.MILLISECONDS, 100); |
|
Ilya Sherman
2015/06/03 22:07:31
nit: Could you please spell "3 * 60 * 1000" as Tim
Ilya Sherman
2015/06/03 22:07:31
nit: Technically, the minimum value for a time his
Benoit L
2015/06/04 11:16:29
Done.
Benoit L
2015/06/04 11:16:29
Done.
|
| + } |
| + } |
| + |
| + /** |
| * Transfers a prerendered WebContents if one exists. |
| * |
| * This resets the internal WebContents; a subsequent call to this method |
| @@ -198,9 +267,9 @@ class ChromeBrowserConnection extends IBrowserConnectionService.Stub { |
| */ |
| boolean deliverOnUserNavigationCallback(long sessionId, String url, Bundle extras) { |
| synchronized (mLock) { |
| - if (mSessionIdToUid.get(sessionId) == null) return false; |
| - int uid = mSessionIdToUid.get(sessionId); |
| - IBrowserConnectionCallback cb = mUidToCallback.get(uid); |
| + SessionParams sessionParams = mSessionParams.get(sessionId); |
| + if (sessionParams == null) return false; |
| + IBrowserConnectionCallback cb = mUidToCallback.get(sessionParams.mUid); |
| if (cb == null) return false; |
| try { |
| cb.onUserNavigation(sessionId, url, extras); |
| @@ -227,16 +296,16 @@ class ChromeBrowserConnection extends IBrowserConnectionService.Stub { |
| // be at least equal to the application's one. This binds to a dummy |
| // service (no calls to this service are made). |
| if (intent == null || intent.getComponent() == null) return false; |
| - int uid; |
| + SessionParams sessionParams; |
| synchronized (mLock) { |
| - if (mSessionIdToUid.get(sessionId) == null) return false; |
| - uid = mSessionIdToUid.get(sessionId); |
| + sessionParams = mSessionParams.get(sessionId); |
| + if (sessionParams == null) return false; |
| } |
| String packageName = intent.getComponent().getPackageName(); |
| PackageManager pm = mApplication.getApplicationContext().getPackageManager(); |
| // Only binds to the application associated to this session ID. |
| + int uid = sessionParams.mUid; |
| if (!Arrays.asList(pm.getPackagesForUid(uid)).contains(packageName)) return false; |
| - |
| Intent serviceIntent = new Intent().setComponent(intent.getComponent()); |
| // This ServiceConnection doesn't handle disconnects. This is on |
| // purpose, as it occurs when the remote process has died. Since the |
| @@ -256,7 +325,7 @@ class ChromeBrowserConnection extends IBrowserConnectionService.Stub { |
| } catch (SecurityException e) { |
| return false; |
| } |
| - if (ok) mSessionIdToServiceConnection.put(sessionId, connection); |
| + if (ok) sessionParams.setServiceConnection(connection); |
| return ok; |
| } |
| @@ -268,10 +337,14 @@ class ChromeBrowserConnection extends IBrowserConnectionService.Stub { |
| * @param sessionId Session ID, as provided to {@link keepAliveForSessionId}. |
| */ |
| void dontKeepAliveForSessionId(long sessionId) { |
| - ServiceConnection connection = mSessionIdToServiceConnection.get(sessionId); |
| - if (connection == null) return; |
| - mSessionIdToServiceConnection.remove(sessionId); |
| - mApplication.getApplicationContext().unbindService(connection); |
| + SessionParams sessionParams; |
| + synchronized (mLock) { |
| + sessionParams = mSessionParams.get(sessionId); |
| + } |
| + if (sessionParams == null || sessionParams.getServiceConnection() == null) return; |
| + ServiceConnection serviceConnection = sessionParams.getServiceConnection(); |
| + sessionParams.setServiceConnection(null); |
| + mApplication.getApplicationContext().unbindService(serviceConnection); |
| } |
| /** |
| @@ -296,11 +369,11 @@ class ChromeBrowserConnection extends IBrowserConnectionService.Stub { |
| List<Long> keysToRemove = new ArrayList<Long>(); |
| // TODO(lizeb): If iterating through all the session IDs is too costly, |
| // use two mappings. |
| - for (int i = 0; i < mSessionIdToUid.size(); i++) { |
| - if (mSessionIdToUid.valueAt(i) == uid) keysToRemove.add(mSessionIdToUid.keyAt(i)); |
| + for (int i = 0; i < mSessionParams.size(); i++) { |
| + if (mSessionParams.valueAt(i).mUid == uid) keysToRemove.add(mSessionParams.keyAt(i)); |
| } |
| for (Long sessionId : keysToRemove) { |
| - mSessionIdToUid.remove(sessionId); |
| + mSessionParams.remove(sessionId); |
| } |
| mUidToCallback.remove(uid); |
| } |