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

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/ChildConnectionAllocator.java

Issue 2795113003: Factor out inner-classes out of ChildProcessLauncher. (Closed)
Patch Set: Factor out ChildProcessConnection. Created 3 years, 8 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 2017 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.content.browser;
6
7 import android.content.ComponentName;
8 import android.content.Context;
9 import android.content.pm.ApplicationInfo;
10 import android.content.pm.PackageManager;
11 import android.os.Bundle;
12 import android.text.TextUtils;
13
14 import org.chromium.base.Log;
15 import org.chromium.base.VisibleForTesting;
16 import org.chromium.content.app.PrivilegedProcessService;
17 import org.chromium.content.app.SandboxedProcessService;
18
19 import java.util.ArrayList;
20 import java.util.LinkedList;
21 import java.util.Map;
22 import java.util.Queue;
23 import java.util.concurrent.ConcurrentHashMap;
24
25 import javax.annotation.concurrent.GuardedBy;
26
27 /**
28 * This class is responsible for allocating and managing connections to child
29 * process services. These connections are in a pool (the services are defined
30 * in the AndroidManifest.xml).
31 */
32 public class ChildConnectionAllocator {
33 private static final String TAG = "ChildConnAllocator";
34
35 private static final String NUM_SANDBOXED_SERVICES_KEY =
36 "org.chromium.content.browser.NUM_SANDBOXED_SERVICES";
37 private static final String NUM_PRIVILEGED_SERVICES_KEY =
38 "org.chromium.content.browser.NUM_PRIVILEGED_SERVICES";
39 private static final String SANDBOXED_SERVICES_NAME_KEY =
40 "org.chromium.content.browser.SANDBOXED_SERVICES_NAME";
41
42 // Connections to services. Indices of the array correspond to the service n umbers.
43 private final ChildProcessConnection[] mChildProcessConnections;
44
45 private final String mChildClassName;
46 private final boolean mInSandbox;
47
48 private final Object mConnectionLock = new Object();
49
50 // The list of free (not bound) service indices.
51 @GuardedBy("mConnectionLock")
52 private final ArrayList<Integer> mFreeConnectionIndices;
53
54 // Each Allocator keeps a queue for the pending spawn data. Once a connectio n is free, we
55 // dequeue the pending spawn data from the same allocator as the connection.
56 @GuardedBy("mConnectionLock")
57 private final Queue<ChildSpawnData> mPendingSpawnQueue = new LinkedList<>();
58
59 private static final Object sAllocatorLock = new Object();
boliu 2017/04/12 00:20:16 nit: move static vars above instance vars, but bel
Jay Civelli 2017/04/12 00:47:15 Done.
60
61 // Map from package name to ChildConnectionAllocator.
62 @GuardedBy("sAllocatorLock")
63 private static Map<String, ChildConnectionAllocator> sSandboxedChildConnecti onAllocatorMap;
64
65 // As the default value it uses PrivilegedProcessService0.
boliu 2017/04/12 00:20:15 nit: this comment makes no sense to me..
Jay Civelli 2017/04/12 00:47:15 Me neither, I had just moved it from its original
66 @GuardedBy("sAllocatorLock")
67 private static ChildConnectionAllocator sPrivilegedChildConnectionAllocator;
68
69 // Used by test to override the default sandboxed service settings.
70 private static int sSandboxedServicesCountForTesting = -1;
71 private static String sSandboxedServicesNameForTesting;
72
73 public static ChildConnectionAllocator getAllocator(
74 Context context, String packageName, boolean inSandbox) {
75 synchronized (sAllocatorLock) {
76 if (!inSandbox) {
77 if (sPrivilegedChildConnectionAllocator == null) {
78 sPrivilegedChildConnectionAllocator = new ChildConnectionAll ocator(false,
79 getNumberOfServices(context, false, packageName),
80 getClassNameOfService(context, false, packageName));
81 }
82 return sPrivilegedChildConnectionAllocator;
83 }
84
85 if (sSandboxedChildConnectionAllocatorMap == null) {
86 sSandboxedChildConnectionAllocatorMap =
87 new ConcurrentHashMap<String, ChildConnectionAllocator>( );
88 }
89 if (!sSandboxedChildConnectionAllocatorMap.containsKey(packageName)) {
90 Log.w(TAG,
91 "Create a new ChildConnectionAllocator with package name = %s,"
92 + " inSandbox = true",
93 packageName);
94 sSandboxedChildConnectionAllocatorMap.put(packageName,
95 new ChildConnectionAllocator(true,
96 getNumberOfServices(context, true, packageName),
97 getClassNameOfService(context, true, packageName )));
98 }
99 return sSandboxedChildConnectionAllocatorMap.get(packageName);
100 // TODO(pkotwicz|hanxi): Figure out when old allocators should be re moved from
101 // {@code sSandboxedChildConnectionAllocatorMap}.
102 }
103 }
104
105 @VisibleForTesting
106 public static void setSanboxServicesSettingsForTesting(int serviceCount, Str ing serviceName) {
107 sSandboxedServicesCountForTesting = serviceCount;
108 sSandboxedServicesNameForTesting = serviceName;
109 }
110
111 private ChildConnectionAllocator(
112 boolean inSandbox, int numChildServices, String serviceClassName) {
113 mChildProcessConnections = new ChildProcessConnectionImpl[numChildServic es];
114 mFreeConnectionIndices = new ArrayList<Integer>(numChildServices);
115 for (int i = 0; i < numChildServices; i++) {
116 mFreeConnectionIndices.add(i);
117 }
118 mChildClassName = serviceClassName;
119 mInSandbox = inSandbox;
120 }
121
122 // Allocates or enqueues. If there are no free slots, returns null and enque ues the spawn data.
123 public ChildProcessConnection allocate(ChildSpawnData spawnData,
124 ChildProcessConnection.DeathCallback deathCallback, Bundle childProc essCommonParameters,
125 boolean queueIfNoSlotAvailable) {
126 assert spawnData.isInSandbox() == mInSandbox;
127 synchronized (mConnectionLock) {
128 if (mFreeConnectionIndices.isEmpty()) {
129 Log.d(TAG, "Ran out of services to allocate.");
130 if (queueIfNoSlotAvailable) {
131 mPendingSpawnQueue.add(spawnData);
132 }
133 return null;
134 }
135 int slot = mFreeConnectionIndices.remove(0);
136 assert mChildProcessConnections[slot] == null;
137 mChildProcessConnections[slot] = new ChildProcessConnectionImpl(spaw nData.getContext(),
138 slot, mInSandbox, deathCallback, mChildClassName, childProce ssCommonParameters,
139 spawnData.isAlwaysInForeground(), spawnData.getCreationParam s());
140 Log.d(TAG, "Allocator allocated a connection, sandbox: %b, slot: %d" , mInSandbox, slot);
141 return mChildProcessConnections[slot];
142 }
143 }
144
145 // Also return the first ChildSpawnData in the pending queue, if any.
146 public ChildSpawnData free(ChildProcessConnection connection) {
147 synchronized (mConnectionLock) {
148 int slot = connection.getServiceNumber();
149 if (mChildProcessConnections[slot] != connection) {
150 int occupier = mChildProcessConnections[slot] == null
151 ? -1
152 : mChildProcessConnections[slot].getServiceNumber();
153 Log.e(TAG,
154 "Unable to find connection to free in slot: %d "
155 + "already occupied by service: %d",
156 slot, occupier);
157 assert false;
158 } else {
159 mChildProcessConnections[slot] = null;
160 assert !mFreeConnectionIndices.contains(slot);
161 mFreeConnectionIndices.add(slot);
162 Log.d(TAG, "Allocator freed a connection, sandbox: %b, slot: %d" , mInSandbox, slot);
163 }
164 return mPendingSpawnQueue.poll();
165 }
166 }
167
168 public boolean isFreeConnectionAvailable() {
169 synchronized (mConnectionLock) {
170 return !mFreeConnectionIndices.isEmpty();
171 }
172 }
173
174 private static String getClassNameOfService(
boliu 2017/04/12 00:20:15 nit: same, group static methods together, perhaps
Jay Civelli 2017/04/12 00:47:15 Moved them up.
175 Context context, boolean inSandbox, String packageName) {
176 if (!inSandbox) {
177 return PrivilegedProcessService.class.getName();
178 }
179
180 if (!TextUtils.isEmpty(sSandboxedServicesNameForTesting)) {
181 return sSandboxedServicesNameForTesting;
182 }
183
184 String serviceName = null;
185 try {
186 PackageManager packageManager = context.getPackageManager();
187 ApplicationInfo appInfo =
188 packageManager.getApplicationInfo(packageName, PackageManage r.GET_META_DATA);
189 if (appInfo.metaData != null) {
190 serviceName = appInfo.metaData.getString(SANDBOXED_SERVICES_NAME _KEY);
191 }
192 } catch (PackageManager.NameNotFoundException e) {
193 throw new RuntimeException("Could not get application info.");
194 }
195
196 if (serviceName != null) {
197 // Check that the service exists.
198 try {
199 PackageManager packageManager = context.getPackageManager();
200 // PackageManager#getServiceInfo() throws an exception if the se rvice does not
201 // exist.
202 packageManager.getServiceInfo(new ComponentName(packageName, ser viceName + "0"), 0);
203 return serviceName;
204 } catch (PackageManager.NameNotFoundException e) {
205 throw new RuntimeException(
206 "Illegal meta data value: the child service doesn't exis t");
207 }
208 }
209 return SandboxedProcessService.class.getName();
210 }
211
212 static int getNumberOfServices(Context context, boolean inSandbox, String pa ckageName) {
213 int numServices = -1;
214 if (inSandbox && sSandboxedServicesCountForTesting != -1) {
215 numServices = sSandboxedServicesCountForTesting;
216 } else {
217 try {
218 PackageManager packageManager = context.getPackageManager();
219 ApplicationInfo appInfo = packageManager.getApplicationInfo(
220 packageName, PackageManager.GET_META_DATA);
221 if (appInfo.metaData != null) {
222 numServices = appInfo.metaData.getInt(
223 inSandbox ? NUM_SANDBOXED_SERVICES_KEY : NUM_PRIVILE GED_SERVICES_KEY,
224 -1);
225 }
226 } catch (PackageManager.NameNotFoundException e) {
227 throw new RuntimeException("Could not get application info");
228 }
229 }
230 if (numServices < 0) {
231 throw new RuntimeException("Illegal meta data value for number of ch ild services");
232 }
233 return numServices;
234 }
235
236 /** @return the count of connections managed by the allocator */
237 @VisibleForTesting
238 int allocatedConnectionsCountForTesting() {
239 synchronized (mConnectionLock) {
240 return mChildProcessConnections.length - mFreeConnectionIndices.size ();
241 }
242 }
243
244 @VisibleForTesting
245 ChildProcessConnection[] connectionArrayForTesting() {
246 return mChildProcessConnections;
247 }
248
249 @VisibleForTesting
250 void enqueuePendingQueueForTesting(ChildSpawnData spawnData) {
251 synchronized (mConnectionLock) {
252 mPendingSpawnQueue.add(spawnData);
253 }
254 }
255
256 @VisibleForTesting
257 int pendingSpawnsCountForTesting() {
258 synchronized (mConnectionLock) {
259 return mPendingSpawnQueue.size();
260 }
261 }
262 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698