Index: chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java |
index 0115813369bf632813b502d3e7b4c4da02020018..0538232d2652d9d2d66cad1e0156528347de2386 100644 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java |
@@ -6,11 +6,8 @@ package org.chromium.chrome.browser.customtabs; |
import android.app.ActivityManager; |
import android.app.Application; |
-import android.content.ComponentName; |
import android.content.Context; |
import android.content.Intent; |
-import android.content.ServiceConnection; |
-import android.content.pm.PackageManager; |
import android.content.res.Resources; |
import android.graphics.Bitmap; |
import android.graphics.Point; |
@@ -22,8 +19,6 @@ import android.os.Build; |
import android.os.Bundle; |
import android.os.IBinder; |
import android.os.Process; |
-import android.os.RemoteException; |
-import android.os.SystemClock; |
import android.support.customtabs.CustomTabsIntent; |
import android.support.customtabs.ICustomTabsCallback; |
import android.support.customtabs.ICustomTabsService; |
@@ -36,7 +31,6 @@ import org.chromium.base.ThreadUtils; |
import org.chromium.base.VisibleForTesting; |
import org.chromium.base.annotations.SuppressFBWarnings; |
import org.chromium.base.library_loader.ProcessInitException; |
-import org.chromium.base.metrics.RecordHistogram; |
import org.chromium.chrome.R; |
import org.chromium.chrome.browser.ChromeApplication; |
import org.chromium.chrome.browser.IntentHandler; |
@@ -55,14 +49,9 @@ import org.chromium.content_public.common.Referrer; |
import java.io.BufferedReader; |
import java.io.FileReader; |
import java.io.IOException; |
-import java.util.ArrayList; |
-import java.util.Arrays; |
-import java.util.HashMap; |
import java.util.List; |
-import java.util.Map; |
import java.util.concurrent.Callable; |
import java.util.concurrent.ExecutionException; |
-import java.util.concurrent.TimeUnit; |
import java.util.concurrent.atomic.AtomicBoolean; |
import java.util.concurrent.atomic.AtomicReference; |
@@ -78,12 +67,6 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
static final String NO_PRERENDERING_KEY = |
"android.support.customtabs.maylaunchurl.NO_PRERENDERING"; |
- // Values for the "CustomTabs.PredictionStatus" UMA histogram. Append-only. |
- private static final int NO_PREDICTION = 0; |
- private static final int GOOD_PREDICTION = 1; |
- private static final int BAD_PREDICTION = 2; |
- private static final int PREDICTION_STATUS_COUNT = 3; |
- |
private static AtomicReference<CustomTabsConnection> sInstance = |
new AtomicReference<CustomTabsConnection>(); |
@@ -106,63 +89,11 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
protected final Application mApplication; |
private final AtomicBoolean mWarmupHasBeenCalled = new AtomicBoolean(); |
+ private final ClientManager mClientManager; |
private ExternalPrerenderHandler mExternalPrerenderHandler; |
private PrerenderedUrlParams mPrerender; |
private WebContents mSpareWebContents; |
- /** Per-session values. */ |
- private static class SessionParams { |
- public final int mUid; |
- public final Referrer mReferrer; |
- public final ICustomTabsCallback mCallback; |
- public final IBinder.DeathRecipient mDeathRecipient; |
- private ServiceConnection mServiceConnection; |
- private String mPredictedUrl; |
- private long mLastMayLaunchUrlTimestamp; |
- |
- public SessionParams(Context context, int uid, ICustomTabsCallback callback, |
- IBinder.DeathRecipient deathRecipient) { |
- mUid = uid; |
- mCallback = callback; |
- mDeathRecipient = deathRecipient; |
- mServiceConnection = null; |
- mPredictedUrl = null; |
- mLastMayLaunchUrlTimestamp = 0; |
- mReferrer = constructReferrer(context); |
- } |
- |
- private Referrer constructReferrer(Context context) { |
- PackageManager packageManager = context.getPackageManager(); |
- String[] packageList = packageManager.getPackagesForUid(mUid); |
- if (packageList.length != 1 || TextUtils.isEmpty(packageList[0])) return null; |
- return IntentHandler.constructValidReferrerForAuthority(packageList[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 = new Object(); |
- private final Map<IBinder, SessionParams> mSessionParams = new HashMap<>(); |
- |
/** |
* <strong>DO NOT CALL</strong> |
* Public to be instanciable from {@link ChromeApplication}. This is however |
@@ -171,9 +102,7 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
public CustomTabsConnection(Application application) { |
super(); |
mApplication = application; |
- synchronized (mLock) { |
- RequestThrottler.purgeOldEntries(application); |
- } |
+ mClientManager = new ClientManager(mApplication); |
} |
/** |
@@ -190,37 +119,13 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
@Override |
public boolean newSession(ICustomTabsCallback callback) { |
- if (callback == null) return false; |
- final int uid = Binder.getCallingUid(); |
- final IBinder session = callback.asBinder(); |
- IBinder.DeathRecipient deathRecipient = |
- new IBinder.DeathRecipient() { |
- @Override |
- public void binderDied() { |
- ThreadUtils.postOnUiThread(new Runnable() { |
- @Override |
- public void run() { |
- synchronized (mLock) { |
- cleanupAlreadyLocked(session); |
- } |
- } |
- }); |
- } |
- }; |
- SessionParams sessionParams = |
- new SessionParams(mApplication, uid, callback, deathRecipient); |
- synchronized (mLock) { |
- if (mSessionParams.containsKey(session)) return false; |
- try { |
- callback.asBinder().linkToDeath(deathRecipient, 0); |
- } catch (RemoteException e) { |
- // The return code doesn't matter, because this executes when |
- // the caller has died. |
- return false; |
+ ClientManager.DisconnectCallback onDisconnect = new ClientManager.DisconnectCallback() { |
+ @Override |
+ public void run(IBinder session) { |
+ cancelPrerender(session); |
} |
- mSessionParams.put(session, sessionParams); |
- } |
- return true; |
+ }; |
+ return mClientManager.newSession(callback, Binder.getCallingUid(), onDisconnect); |
} |
@Override |
@@ -292,12 +197,8 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
final boolean noPrerendering = |
extras != null ? extras.getBoolean(NO_PRERENDERING_KEY, false) : false; |
final int uid = Binder.getCallingUid(); |
- synchronized (mLock) { |
- SessionParams sessionParams = mSessionParams.get(session); |
- if (sessionParams == null || sessionParams.mUid != uid) return false; |
- sessionParams.setPredictionMetrics(urlString, SystemClock.elapsedRealtime()); |
- RequestThrottler throttler = RequestThrottler.getForUid(mApplication, uid); |
- if (!throttler.updateStatsAndReturnWhetherAllowed()) return false; |
+ if (!mClientManager.updateStatsAndReturnWhetherAllowed(session, uid, urlString)) { |
+ return false; |
} |
ThreadUtils.postOnUiThread(new Runnable() { |
@Override |
@@ -373,31 +274,7 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
* This is used for accounting. |
*/ |
void registerLaunch(IBinder session, String url) { |
- int outcome; |
- long elapsedTimeMs = -1; |
- synchronized (mLock) { |
- SessionParams sessionParams = mSessionParams.get(session); |
- 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); |
- if (outcome == GOOD_PREDICTION) { |
- RequestThrottler.getForUid(mApplication, sessionParams.mUid) |
- .registerSuccess(url); |
- } |
- } |
- } |
- RecordHistogram.recordEnumeratedHistogram( |
- "CustomTabs.PredictionStatus", outcome, PREDICTION_STATUS_COUNT); |
- if (outcome == GOOD_PREDICTION) { |
- RecordHistogram.recordCustomTimesHistogram("CustomTabs.PredictionToLaunch", |
- elapsedTimeMs, 1, TimeUnit.MINUTES.toMillis(3), TimeUnit.MILLISECONDS, 100); |
- } |
+ mClientManager.registerLaunch(session, url); |
} |
/** |
@@ -446,16 +323,7 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
} |
public Referrer getReferrerForSession(IBinder session) { |
- if (!mSessionParams.containsKey(session)) return null; |
- return mSessionParams.get(session).mReferrer; |
- } |
- |
- private ICustomTabsCallback getCallbackForSession(IBinder session) { |
- synchronized (mLock) { |
- SessionParams sessionParams = mSessionParams.get(session); |
- if (sessionParams == null) return null; |
- return sessionParams.mCallback; |
- } |
+ return mClientManager.getReferrerForSession(session); |
} |
/** |
@@ -469,7 +337,7 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
* @return true for success. |
*/ |
boolean notifyNavigationEvent(IBinder session, int navigationEvent) { |
- ICustomTabsCallback callback = getCallbackForSession(session); |
+ ICustomTabsCallback callback = mClientManager.getCallbackForSession(session); |
if (callback == null) return false; |
try { |
callback.onNavigationEvent(navigationEvent, null); |
@@ -494,41 +362,7 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
* @return true for success. |
*/ |
boolean keepAliveForSession(IBinder session, Intent intent) { |
- // When an application is bound to a service, its priority is raised to |
- // 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; |
- SessionParams sessionParams; |
- synchronized (mLock) { |
- sessionParams = mSessionParams.get(session); |
- if (sessionParams == null) return false; |
- } |
- String packageName = intent.getComponent().getPackageName(); |
- PackageManager pm = mApplication.getApplicationContext().getPackageManager(); |
- // Only binds to the application associated to this session. |
- 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 |
- // only use of this connection is to keep the application alive, |
- // re-connecting would just re-create the process, but the application |
- // state has been lost at that point, the callbacks invalidated, etc. |
- ServiceConnection connection = new ServiceConnection() { |
- @Override |
- public void onServiceConnected(ComponentName name, IBinder service) {} |
- @Override |
- public void onServiceDisconnected(ComponentName name) {} |
- }; |
- boolean ok; |
- try { |
- ok = mApplication.getApplicationContext().bindService( |
- serviceIntent, connection, Context.BIND_AUTO_CREATE); |
- } catch (SecurityException e) { |
- return false; |
- } |
- if (ok) sessionParams.setServiceConnection(connection); |
- return ok; |
+ return mClientManager.keepAliveForSession(session, intent); |
} |
/** |
@@ -539,14 +373,7 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
* @param session The Binder object identifying the session. |
*/ |
void dontKeepAliveForSession(IBinder session) { |
- SessionParams sessionParams; |
- synchronized (mLock) { |
- sessionParams = mSessionParams.get(session); |
- if (sessionParams == null || sessionParams.getServiceConnection() == null) return; |
- } |
- ServiceConnection serviceConnection = sessionParams.getServiceConnection(); |
- sessionParams.setServiceConnection(null); |
- mApplication.getApplicationContext().unbindService(serviceConnection); |
+ mClientManager.dontKeepAliveForSession(session); |
} |
/** |
@@ -613,23 +440,7 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
@VisibleForTesting |
void cleanupAll() { |
ThreadUtils.assertOnUiThread(); |
- synchronized (mLock) { |
- List<IBinder> sessions = new ArrayList<>(mSessionParams.keySet()); |
- for (IBinder session : sessions) cleanupAlreadyLocked(session); |
- } |
- } |
- |
- /** |
- * Called when a remote client has died. |
- */ |
- private void cleanupAlreadyLocked(IBinder session) { |
- ThreadUtils.assertOnUiThread(); |
- SessionParams params = mSessionParams.get(session); |
- if (params == null) return; |
- mSessionParams.remove(session); |
- IBinder binder = params.mCallback.asBinder(); |
- binder.unlinkToDeath(params.mDeathRecipient, 0); |
- cancelPrerender(session); |
+ mClientManager.cleanupAll(); |
} |
private boolean mayPrerender() { |
@@ -663,9 +474,7 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
// Last one wins and cancels the previous prerender. |
cancelPrerender(null); |
if (TextUtils.isEmpty(url)) return; |
- synchronized (mLock) { |
- if (!RequestThrottler.getForUid(mApplication, uid).isPrerenderingAllowed()) return; |
- } |
+ if (!mClientManager.isPrerenderingAllowed(uid)) return; |
Intent extrasIntent = new Intent(); |
if (extras != null) extrasIntent.putExtras(extras); |
if (IntentHandler.getExtraHeadersFromIntent(extrasIntent) != null) return; |
@@ -682,9 +491,7 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
WebContents webContents = mExternalPrerenderHandler.addPrerender( |
Profile.getLastUsedProfile(), url, referrer, contentSize.x, contentSize.y); |
if (webContents != null) { |
- synchronized (mLock) { |
- RequestThrottler.getForUid(mApplication, uid).registerPrerenderRequest(url); |
- } |
+ mClientManager.registerPrerenderRequest(uid, url); |
mPrerender = new PrerenderedUrlParams(session, webContents, url, referrer, extras); |
} |
} |
@@ -720,8 +527,6 @@ public class CustomTabsConnection extends ICustomTabsService.Stub { |
@VisibleForTesting |
void resetThrottling(Context context, int uid) { |
- synchronized (mLock) { |
- RequestThrottler.getForUid(context, uid).reset(); |
- } |
+ mClientManager.resetThrottling(uid); |
} |
} |