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.content.ComponentName; | 7 import android.content.ComponentName; |
8 import android.content.Context; | 8 import android.content.Context; |
9 import android.content.Intent; | 9 import android.content.Intent; |
10 import android.content.ServiceConnection; | 10 import android.content.ServiceConnection; |
11 import android.content.pm.PackageManager; | 11 import android.content.pm.PackageManager; |
12 import android.os.IBinder; | 12 import android.os.IBinder; |
13 import android.os.RemoteException; | 13 import android.os.RemoteException; |
14 import android.os.SystemClock; | 14 import android.os.SystemClock; |
15 import android.support.customtabs.ICustomTabsCallback; | 15 import android.support.customtabs.ICustomTabsCallback; |
16 import android.text.TextUtils; | 16 import android.text.TextUtils; |
| 17 import android.util.SparseBooleanArray; |
17 | 18 |
18 import org.chromium.base.ThreadUtils; | 19 import org.chromium.base.ThreadUtils; |
| 20 import org.chromium.base.VisibleForTesting; |
19 import org.chromium.base.annotations.SuppressFBWarnings; | 21 import org.chromium.base.annotations.SuppressFBWarnings; |
20 import org.chromium.base.metrics.RecordHistogram; | 22 import org.chromium.base.metrics.RecordHistogram; |
21 import org.chromium.chrome.browser.IntentHandler; | 23 import org.chromium.chrome.browser.IntentHandler; |
22 import org.chromium.content_public.common.Referrer; | 24 import org.chromium.content_public.common.Referrer; |
23 | 25 |
24 import java.util.ArrayList; | 26 import java.util.ArrayList; |
25 import java.util.Arrays; | 27 import java.util.Arrays; |
26 import java.util.HashMap; | 28 import java.util.HashMap; |
27 import java.util.List; | 29 import java.util.List; |
28 import java.util.Map; | 30 import java.util.Map; |
29 import java.util.concurrent.TimeUnit; | 31 import java.util.concurrent.TimeUnit; |
30 | 32 |
31 /** Manages the clients' state for Custom Tabs. This class is threadsafe. */ | 33 /** Manages the clients' state for Custom Tabs. This class is threadsafe. */ |
32 class ClientManager { | 34 class ClientManager { |
33 // Values for the "CustomTabs.PredictionStatus" UMA histogram. Append-only. | 35 // Values for the "CustomTabs.PredictionStatus" UMA histogram. Append-only. |
34 private static final int NO_PREDICTION = 0; | 36 private static final int NO_PREDICTION = 0; |
35 private static final int GOOD_PREDICTION = 1; | 37 private static final int GOOD_PREDICTION = 1; |
36 private static final int BAD_PREDICTION = 2; | 38 private static final int BAD_PREDICTION = 2; |
37 private static final int PREDICTION_STATUS_COUNT = 3; | 39 private static final int PREDICTION_STATUS_COUNT = 3; |
| 40 // Values for the "CustomTabs.CalledWarmup" UMA histogram. Append-only. |
| 41 @VisibleForTesting static final int NO_SESSION_NO_WARMUP = 0; |
| 42 @VisibleForTesting static final int NO_SESSION_WARMUP = 1; |
| 43 @VisibleForTesting static final int SESSION_NO_WARMUP_ALREADY_CALLED = 2; |
| 44 @VisibleForTesting static final int SESSION_NO_WARMUP_NOT_CALLED = 3; |
| 45 @VisibleForTesting static final int SESSION_WARMUP = 4; |
| 46 @VisibleForTesting static final int SESSION_WARMUP_COUNT = 5; |
38 | 47 |
39 /** Per-session values. */ | 48 /** Per-session values. */ |
40 private static class SessionParams { | 49 private static class SessionParams { |
41 public final int uid; | 50 public final int uid; |
42 public final Referrer referrer; | 51 public final Referrer referrer; |
43 public final ICustomTabsCallback callback; | 52 public final ICustomTabsCallback callback; |
44 public final IBinder.DeathRecipient deathRecipient; | 53 public final IBinder.DeathRecipient deathRecipient; |
45 private ServiceConnection mKeepAliveConnection = null; | 54 private ServiceConnection mKeepAliveConnection = null; |
46 private String mPredictedUrl = null; | 55 private String mPredictedUrl = null; |
47 private long mLastMayLaunchUrlTimestamp = 0; | 56 private long mLastMayLaunchUrlTimestamp = 0; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
81 public long getLastMayLaunchUrlTimestamp() { | 90 public long getLastMayLaunchUrlTimestamp() { |
82 return mLastMayLaunchUrlTimestamp; | 91 return mLastMayLaunchUrlTimestamp; |
83 } | 92 } |
84 } | 93 } |
85 | 94 |
86 /** To be called when a client gets disconnected. */ | 95 /** To be called when a client gets disconnected. */ |
87 public interface DisconnectCallback { public void run(IBinder session); } | 96 public interface DisconnectCallback { public void run(IBinder session); } |
88 | 97 |
89 private final Context mContext; | 98 private final Context mContext; |
90 private final Map<IBinder, SessionParams> mSessionParams = new HashMap<>(); | 99 private final Map<IBinder, SessionParams> mSessionParams = new HashMap<>(); |
| 100 private final SparseBooleanArray mUidHasCalledWarmup = new SparseBooleanArra
y(); |
| 101 private boolean mWarmupHasBeenCalled = false; |
91 | 102 |
92 public ClientManager(Context context) { | 103 public ClientManager(Context context) { |
93 mContext = context.getApplicationContext(); | 104 mContext = context.getApplicationContext(); |
94 RequestThrottler.purgeOldEntries(mContext); | 105 RequestThrottler.purgeOldEntries(mContext); |
95 } | 106 } |
96 | 107 |
97 /** Creates a new session. | 108 /** Creates a new session. |
98 * | 109 * |
99 * @param cb Callback provided by the client. | 110 * @param cb Callback provided by the client. |
100 * @param uid Client UID, as returned by Binder.getCallingUid(), | 111 * @param uid Client UID, as returned by Binder.getCallingUid(), |
(...skipping 24 matching lines...) Expand all Loading... |
125 } catch (RemoteException e) { | 136 } catch (RemoteException e) { |
126 // The return code doesn't matter, because this executes when | 137 // The return code doesn't matter, because this executes when |
127 // the caller has died. | 138 // the caller has died. |
128 return false; | 139 return false; |
129 } | 140 } |
130 mSessionParams.put(session, params); | 141 mSessionParams.put(session, params); |
131 } | 142 } |
132 return true; | 143 return true; |
133 } | 144 } |
134 | 145 |
| 146 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") |
| 147 public synchronized void recordUidHasCalledWarmup(int uid) { |
| 148 mWarmupHasBeenCalled = true; |
| 149 mUidHasCalledWarmup.put(uid, true); |
| 150 } |
| 151 |
135 /** Updates the client behavior stats and returns whether speculation is all
owed. | 152 /** Updates the client behavior stats and returns whether speculation is all
owed. |
136 * | 153 * |
137 * @param session Client session. | 154 * @param session Client session. |
138 * @param uid As returned by Binder.getCallingUid(). | 155 * @param uid As returned by Binder.getCallingUid(). |
139 * @param url Predicted URL. | 156 * @param url Predicted URL. |
140 * @return true if speculation is allowed. | 157 * @return true if speculation is allowed. |
141 */ | 158 */ |
142 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") | 159 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") |
143 public synchronized boolean updateStatsAndReturnWhetherAllowed( | 160 public synchronized boolean updateStatsAndReturnWhetherAllowed( |
144 IBinder session, int uid, String url) { | 161 IBinder session, int uid, String url) { |
145 SessionParams params = mSessionParams.get(session); | 162 SessionParams params = mSessionParams.get(session); |
146 if (params == null || params.uid != uid) return false; | 163 if (params == null || params.uid != uid) return false; |
147 params.setPredictionMetrics(url, SystemClock.elapsedRealtime()); | 164 params.setPredictionMetrics(url, SystemClock.elapsedRealtime()); |
148 RequestThrottler throttler = RequestThrottler.getForUid(mContext, uid); | 165 RequestThrottler throttler = RequestThrottler.getForUid(mContext, uid); |
149 return throttler.updateStatsAndReturnWhetherAllowed(); | 166 return throttler.updateStatsAndReturnWhetherAllowed(); |
150 } | 167 } |
151 | 168 |
| 169 @VisibleForTesting |
| 170 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") |
| 171 synchronized int getWarmupState(IBinder session) { |
| 172 SessionParams params = mSessionParams.get(session); |
| 173 boolean hasValidSession = params != null; |
| 174 boolean hasUidCalledWarmup = hasValidSession && mUidHasCalledWarmup.get(
params.uid); |
| 175 int result = mWarmupHasBeenCalled ? NO_SESSION_WARMUP : NO_SESSION_NO_WA
RMUP; |
| 176 if (hasValidSession) { |
| 177 if (hasUidCalledWarmup) { |
| 178 result = SESSION_WARMUP; |
| 179 } else { |
| 180 result = mWarmupHasBeenCalled ? SESSION_NO_WARMUP_ALREADY_CALLED |
| 181 : SESSION_NO_WARMUP_NOT_CALLED; |
| 182 } |
| 183 } |
| 184 return result; |
| 185 } |
| 186 |
152 /** | 187 /** |
153 * Registers that a client has launched a URL inside a Custom Tab. | 188 * Registers that a client has launched a URL inside a Custom Tab. |
154 */ | 189 */ |
155 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") | 190 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") |
156 public synchronized void registerLaunch(IBinder session, String url) { | 191 public synchronized void registerLaunch(IBinder session, String url) { |
157 int outcome = NO_PREDICTION; | 192 int outcome = NO_PREDICTION; |
158 long elapsedTimeMs = -1; | 193 long elapsedTimeMs = -1; |
159 SessionParams params = mSessionParams.get(session); | 194 SessionParams params = mSessionParams.get(session); |
160 if (params != null) { | 195 if (params != null) { |
161 String predictedUrl = params.getPredictedUrl(); | 196 String predictedUrl = params.getPredictedUrl(); |
162 outcome = predictedUrl == null ? NO_PREDICTION : predictedUrl.equals
(url) | 197 outcome = predictedUrl == null ? NO_PREDICTION : predictedUrl.equals
(url) |
163 ? GOOD_PREDICTION | 198 ? GOOD_PREDICTION |
164 : BAD_PREDICTION; | 199 : BAD_PREDICTION; |
165 long now = SystemClock.elapsedRealtime(); | 200 long now = SystemClock.elapsedRealtime(); |
166 elapsedTimeMs = now - params.getLastMayLaunchUrlTimestamp(); | 201 elapsedTimeMs = now - params.getLastMayLaunchUrlTimestamp(); |
167 params.setPredictionMetrics(null, 0); | 202 params.setPredictionMetrics(null, 0); |
168 if (outcome == GOOD_PREDICTION) { | 203 if (outcome == GOOD_PREDICTION) { |
169 RequestThrottler.getForUid(mContext, params.uid).registerSuccess
(url); | 204 RequestThrottler.getForUid(mContext, params.uid).registerSuccess
(url); |
170 } | 205 } |
171 } | 206 } |
172 RecordHistogram.recordEnumeratedHistogram( | 207 RecordHistogram.recordEnumeratedHistogram( |
173 "CustomTabs.PredictionStatus", outcome, PREDICTION_STATUS_COUNT)
; | 208 "CustomTabs.PredictionStatus", outcome, PREDICTION_STATUS_COUNT)
; |
174 if (outcome == GOOD_PREDICTION) { | 209 if (outcome == GOOD_PREDICTION) { |
175 RecordHistogram.recordCustomTimesHistogram("CustomTabs.PredictionToL
aunch", | 210 RecordHistogram.recordCustomTimesHistogram("CustomTabs.PredictionToL
aunch", |
176 elapsedTimeMs, 1, TimeUnit.MINUTES.toMillis(3), TimeUnit.MIL
LISECONDS, 100); | 211 elapsedTimeMs, 1, TimeUnit.MINUTES.toMillis(3), TimeUnit.MIL
LISECONDS, 100); |
177 } | 212 } |
| 213 RecordHistogram.recordEnumeratedHistogram( |
| 214 "CustomTabs.WarmupStateOnLaunch", getWarmupState(session), SESSI
ON_WARMUP_COUNT); |
178 } | 215 } |
179 | 216 |
180 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") | 217 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") |
181 public synchronized Referrer getReferrerForSession(IBinder session) { | 218 public synchronized Referrer getReferrerForSession(IBinder session) { |
182 SessionParams params = mSessionParams.get(session); | 219 SessionParams params = mSessionParams.get(session); |
183 return params != null ? params.referrer : null; | 220 return params != null ? params.referrer : null; |
184 } | 221 } |
185 | 222 |
186 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") | 223 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") |
187 public synchronized ICustomTabsCallback getCallbackForSession(IBinder sessio
n) { | 224 public synchronized ICustomTabsCallback getCallbackForSession(IBinder sessio
n) { |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 public synchronized void cleanupAll() { | 291 public synchronized void cleanupAll() { |
255 List<IBinder> sessions = new ArrayList<>(mSessionParams.keySet()); | 292 List<IBinder> sessions = new ArrayList<>(mSessionParams.keySet()); |
256 for (IBinder session : sessions) cleanupSession(session); | 293 for (IBinder session : sessions) cleanupSession(session); |
257 } | 294 } |
258 | 295 |
259 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") | 296 @SuppressFBWarnings("CHROMIUM_SYNCHRONIZED_METHOD") |
260 private synchronized void cleanupSession(IBinder session) { | 297 private synchronized void cleanupSession(IBinder session) { |
261 SessionParams params = mSessionParams.get(session); | 298 SessionParams params = mSessionParams.get(session); |
262 if (params == null) return; | 299 if (params == null) return; |
263 mSessionParams.remove(session); | 300 mSessionParams.remove(session); |
| 301 mUidHasCalledWarmup.delete(params.uid); |
264 IBinder binder = params.callback.asBinder(); | 302 IBinder binder = params.callback.asBinder(); |
265 binder.unlinkToDeath(params.deathRecipient, 0); | 303 binder.unlinkToDeath(params.deathRecipient, 0); |
266 } | 304 } |
267 } | 305 } |
OLD | NEW |