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

Side by Side Diff: chrome/android/java_staging/src/org/chromium/chrome/browser/hosted/ChromeBrowserConnection.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 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
(Empty)
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
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser.hosted;
6
7 import android.annotation.SuppressLint;
8 import android.app.ActivityManager;
9 import android.app.Application;
10 import android.content.Context;
11 import android.os.Binder;
12 import android.os.Bundle;
13 import android.os.IBinder;
14 import android.os.RemoteException;
15 import android.util.LongSparseArray;
16 import android.util.SparseArray;
17
18 import org.chromium.base.Log;
19 import org.chromium.base.ThreadUtils;
20 import org.chromium.base.annotations.SuppressFBWarnings;
21 import org.chromium.base.library_loader.ProcessInitException;
22 import org.chromium.chrome.browser.ChromiumApplication;
23 import org.chromium.chrome.browser.WarmupManager;
24 import org.chromium.content.browser.ChildProcessLauncher;
25 import org.chromium.content_public.browser.WebContents;
26
27 import java.security.SecureRandom;
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.concurrent.atomic.AtomicBoolean;
31
32 /**
33 * Implementation of the IBrowserConnectionService interface.
34 */
35 class ChromeBrowserConnection extends IBrowserConnectionService.Stub {
36 private static final String TAG = Log.makeTag("ChromeConnection");
37 private static final long RESULT_OK = 0;
38 private static final long RESULT_ERROR = -1;
39
40 private static final Object sConstructionLock = new Object();
41 private static ChromeBrowserConnection sInstance;
42
43 private final Application mApplication;
44 private final AtomicBoolean mWarmupHasBeenCalled;
45
46 private final Object mLock;
47 private final SparseArray<IBrowserConnectionCallback> mUidToCallback;
48 private final LongSparseArray<Integer> mSessionIdToUid;
49
50 private ChromeBrowserConnection(Application application) {
51 super();
52 mApplication = application;
53 mWarmupHasBeenCalled = new AtomicBoolean();
54 mLock = new Object();
55 mUidToCallback = new SparseArray<IBrowserConnectionCallback>();
56 mSessionIdToUid = new LongSparseArray<Integer>();
57 }
58
59 /**
60 * @return The unique instance of ChromeBrowserConnection.
61 */
62 public static ChromeBrowserConnection getInstance(Application application) {
63 synchronized (sConstructionLock) {
64 if (sInstance == null) sInstance = new ChromeBrowserConnection(appli cation);
65 }
66 return sInstance;
67 }
68
69 @Override
70 public long finishSetup(IBrowserConnectionCallback callback) {
71 final int uid = Binder.getCallingUid();
72 synchronized (mLock) {
73 if (mUidToCallback.get(uid) != null) return RESULT_ERROR;
74 try {
75 callback.asBinder().linkToDeath(new IBinder.DeathRecipient() {
76 @Override
77 public void binderDied() {
78 synchronized (mLock) {
79 cleanupAlreadyLocked(uid);
80 }
81 }
82 }, 0);
83 } catch (RemoteException e) {
84 // The return code doesn't matter, because this executes when
85 // the caller has died.
86 return RESULT_ERROR;
87 }
88 mUidToCallback.put(uid, callback);
89 }
90 return RESULT_OK;
91 }
92
93 @Override
94 public long warmup(long flags) {
95 // Here and in mayLaunchUrl(), don't do expensive work for background ap plications.
96 if (!isUidForeground(Binder.getCallingUid())) return RESULT_ERROR;
97 if (!mWarmupHasBeenCalled.compareAndSet(false, true)) return RESULT_OK;
98 // The call is non-blocking and this must execute on the UI thread, post a task.
99 ThreadUtils.postOnUiThread(new Runnable() {
100 @Override
101 @SuppressFBWarnings("DM_EXIT")
102 public void run() {
103 try {
104 // TODO(lizeb): Warm up more of the browser.
105 ChromiumApplication app = (ChromiumApplication) mApplication ;
106 app.startBrowserProcessesAndLoadLibrariesSync(
107 app.getApplicationContext(), true);
108 ChildProcessLauncher.warmUp(app.getApplicationContext());
109 } catch (ProcessInitException e) {
110 Log.e(TAG, "ProcessInitException while starting the browser process.");
111 // Cannot do anything without the native library, and cannot show a
112 // dialog to the user.
113 System.exit(-1);
114 }
115 }
116 });
117 return RESULT_OK;
118 }
119
120 @Override
121 @SuppressLint("TrulyRandom") // TODO(lizeb): Figure out whether using Secure Random is OK.
122 public long newSession() {
123 synchronized (mLock) {
124 long sessionId;
125 SecureRandom randomSource = new SecureRandom();
126 do {
127 sessionId = randomSource.nextLong();
128 // Because Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE.
129 if (sessionId == Long.MIN_VALUE) continue;
130 sessionId = Math.abs(sessionId);
131 } while (sessionId == 0 || mSessionIdToUid.get(sessionId) != null);
132 mSessionIdToUid.put(sessionId, Binder.getCallingUid());
133 return sessionId;
134 }
135 }
136
137 @Override
138 public long mayLaunchUrl(
139 long sessionId, final String url, Bundle extras, List<Bundle> otherL ikelyBundles) {
140 if (!isUidForeground(Binder.getCallingUid())) return RESULT_ERROR;
141 synchronized (mLock) {
142 if (mSessionIdToUid.get(sessionId) == null) return RESULT_ERROR;
143 }
144 ThreadUtils.postOnUiThread(new Runnable() {
145 @Override
146 public void run() {
147 WarmupManager.getInstance().maybePrefetchDnsForUrlInBackground(
148 mApplication.getApplicationContext(), url);
149 }
150 });
151 // TODO(lizeb): Prerendering.
152 return sessionId;
153 }
154
155 /**
156 * Transfers a prerendered WebContents if one exists.
157 *
158 * This resets the internal WebContents; a subsequent call to this method
159 * returns null.
160 *
161 * @param sessionId The session ID, returned by {@link newSession}.
162 * @param url The URL the WebContents is for.
163 * @param extras from the intent.
164 * @return The prerendered WebContents, or null.
165 */
166 WebContents takePrerenderedUrl(long sessionId, String url, Bundle extras) {
167 // TODO(lizeb): Pre-rendering.
168 return null;
169 }
170
171 /**
172 * Calls the onUserNavigation callback for a given sessionId.
173 *
174 * This is non-blocking.
175 *
176 * @param sessionId Session ID associated with the callback
177 * @param url URL the user has navigated to.
178 * @param bundle Reserved for future use.
179 * @return false if there is no client to deliver the callback to.
180 */
181 boolean deliverOnUserNavigationCallback(long sessionId, String url, Bundle e xtras) {
182 synchronized (mLock) {
183 if (mSessionIdToUid.get(sessionId) == null) return false;
184 int uid = mSessionIdToUid.get(sessionId);
185 IBrowserConnectionCallback cb = mUidToCallback.get(uid);
186 if (cb == null) return false;
187 try {
188 cb.onUserNavigation(sessionId, url, extras);
189 } catch (RemoteException e) {
190 return false;
191 }
192 }
193 return true;
194 }
195
196 /**
197 * @return true iff the UID is associated with a process having a foreground importance.
198 */
199 private boolean isUidForeground(int uid) {
200 ActivityManager am =
201 (ActivityManager) mApplication.getSystemService(Context.ACTIVITY _SERVICE);
202 List<ActivityManager.RunningAppProcessInfo> running = am.getRunningAppPr ocesses();
203 for (ActivityManager.RunningAppProcessInfo rpi : running) {
204 boolean isForeground =
205 rpi.importance == ActivityManager.RunningAppProcessInfo.IMPO RTANCE_FOREGROUND;
206 if (rpi.uid == uid && isForeground) return true;
207 }
208 return false;
209 }
210
211 /**
212 * Called when a remote client has died.
213 */
214 private void cleanupAlreadyLocked(int uid) {
215 List<Long> keysToRemove = new ArrayList<Long>();
216 // TODO(lizeb): If iterating through all the session IDs is too costly,
217 // use two mappings.
218 for (int i = 0; i < mSessionIdToUid.size(); i++) {
219 if (mSessionIdToUid.valueAt(i) == uid) keysToRemove.add(mSessionIdTo Uid.keyAt(i));
220 }
221 for (Long sessionId : keysToRemove) {
222 mSessionIdToUid.remove(sessionId);
223 }
224 mUidToCallback.remove(uid);
225 }
226 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698