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.gsa; | 5 package org.chromium.chrome.browser.gsa; |
6 | 6 |
7 import android.annotation.SuppressLint; | 7 import android.annotation.SuppressLint; |
8 import android.app.ActivityManager; | |
9 import android.content.ComponentName; | 8 import android.content.ComponentName; |
10 import android.content.Context; | 9 import android.content.Context; |
11 import android.content.Intent; | 10 import android.content.Intent; |
12 import android.content.ServiceConnection; | 11 import android.content.ServiceConnection; |
13 import android.os.AsyncTask; | |
14 import android.os.Bundle; | 12 import android.os.Bundle; |
15 import android.os.Debug; | |
16 import android.os.Handler; | 13 import android.os.Handler; |
17 import android.os.IBinder; | 14 import android.os.IBinder; |
18 import android.os.Message; | 15 import android.os.Message; |
19 import android.os.Messenger; | 16 import android.os.Messenger; |
20 import android.os.RemoteException; | 17 import android.os.RemoteException; |
21 import android.os.StrictMode; | 18 import android.os.StrictMode; |
22 import android.util.Log; | 19 import android.util.Log; |
23 | 20 |
24 import org.chromium.base.Callback; | 21 import org.chromium.base.Callback; |
25 import org.chromium.base.ContextUtils; | |
26 import org.chromium.base.TraceEvent; | |
27 import org.chromium.base.VisibleForTesting; | |
28 import org.chromium.base.annotations.SuppressFBWarnings; | 22 import org.chromium.base.annotations.SuppressFBWarnings; |
29 import org.chromium.base.metrics.RecordHistogram; | 23 import org.chromium.base.metrics.RecordHistogram; |
30 import org.chromium.chrome.browser.AppHooks; | 24 import org.chromium.chrome.browser.AppHooks; |
31 | 25 |
32 import java.util.List; | |
33 | |
34 /** | 26 /** |
35 * A simple client that connects and talks to the GSAService using Messages. | 27 * A simple client that connects and talks to the GSAService using Messages. |
36 */ | 28 */ |
37 public class GSAServiceClient { | 29 public class GSAServiceClient { |
38 private static final String TAG = "GSAServiceClient"; | 30 private static final String TAG = "GSAServiceClient"; |
39 | 31 |
40 /** | 32 /** |
41 * Constants for gsa communication. These should not change without correspo
nding changes on the | 33 * Constants for gsa communication. These should not change without correspo
nding changes on the |
42 * service side in GSA. | 34 * service side in GSA. |
43 */ | 35 */ |
44 @VisibleForTesting | 36 private static final String GSA_SERVICE = "com.google.android.ssb.action.SSB
_SERVICE"; |
45 static final String GSA_SERVICE = "com.google.android.ssb.action.SSB_SERVICE
"; | |
46 public static final int REQUEST_REGISTER_CLIENT = 2; | 37 public static final int REQUEST_REGISTER_CLIENT = 2; |
47 public static final int RESPONSE_UPDATE_SSB = 3; | 38 public static final int RESPONSE_UPDATE_SSB = 3; |
48 | 39 |
49 public static final String KEY_GSA_STATE = "ssb_service:ssb_state"; | 40 public static final String KEY_GSA_STATE = "ssb_service:ssb_state"; |
50 public static final String KEY_GSA_CONTEXT = "ssb_service:ssb_context"; | 41 public static final String KEY_GSA_CONTEXT = "ssb_service:ssb_context"; |
51 public static final String KEY_GSA_PACKAGE_NAME = "ssb_service:ssb_package_n
ame"; | 42 public static final String KEY_GSA_PACKAGE_NAME = "ssb_service:ssb_package_n
ame"; |
52 public static final String KEY_GSA_SUPPORTS_BROADCAST = | 43 public static final String KEY_GSA_SUPPORTS_BROADCAST = |
53 "ssb_service:chrome_holds_account_update_permission"; | 44 "ssb_service:chrome_holds_account_update_permission"; |
54 | 45 |
55 @VisibleForTesting | |
56 static final int INVALID_PSS = -1; | |
57 | |
58 static final String ACCOUNT_CHANGE_HISTOGRAM = "Search.GsaAccountChangeNotif
icationSource"; | 46 static final String ACCOUNT_CHANGE_HISTOGRAM = "Search.GsaAccountChangeNotif
icationSource"; |
59 // For the histogram above. Append-only. | 47 // For the histogram above. Append-only. |
60 static final int ACCOUNT_CHANGE_SOURCE_SERVICE = 0; | 48 static final int ACCOUNT_CHANGE_SOURCE_SERVICE = 0; |
61 static final int ACCOUNT_CHANGE_SOURCE_BROADCAST = 1; | 49 static final int ACCOUNT_CHANGE_SOURCE_BROADCAST = 1; |
62 static final int ACCOUNT_CHANGE_SOURCE_COUNT = 2; | 50 static final int ACCOUNT_CHANGE_SOURCE_COUNT = 2; |
63 | 51 |
64 private static boolean sHasRecordedPss; | |
65 /** Messenger to handle incoming messages from the service */ | 52 /** Messenger to handle incoming messages from the service */ |
66 private final Messenger mMessenger; | 53 private final Messenger mMessenger; |
67 private final IncomingHandler mHandler; | 54 private final IncomingHandler mHandler; |
68 private final GSAServiceConnection mConnection; | 55 private final GSAServiceConnection mConnection; |
69 private final GSAHelper mGsaHelper; | 56 private final GSAHelper mGsaHelper; |
70 private Context mContext; | 57 private Context mContext; |
71 private Callback<Bundle> mOnMessageReceived; | 58 private Callback<Bundle> mOnMessageReceived; |
72 | 59 |
73 /** Messenger for communicating with service. */ | 60 /** Messenger for communicating with service. */ |
74 private Messenger mService; | 61 private Messenger mService; |
75 private ComponentName mComponentName; | |
76 | 62 |
77 /** | 63 /** |
78 * Handler of incoming messages from service. | 64 * Handler of incoming messages from service. |
79 */ | 65 */ |
80 @SuppressFBWarnings("BC_IMPOSSIBLE_CAST") | 66 @SuppressFBWarnings("BC_IMPOSSIBLE_CAST") |
81 @SuppressLint("HandlerLeak") | 67 @SuppressLint("HandlerLeak") |
82 private class IncomingHandler extends Handler { | 68 private class IncomingHandler extends Handler { |
83 @Override | 69 @Override |
84 public void handleMessage(Message msg) { | 70 public void handleMessage(Message msg) { |
85 if (msg.what != RESPONSE_UPDATE_SSB) { | 71 if (msg.what != RESPONSE_UPDATE_SSB) { |
86 super.handleMessage(msg); | 72 super.handleMessage(msg); |
87 return; | 73 return; |
88 } | 74 } |
89 | 75 |
90 if (mService == null) return; | 76 if (mService == null) return; |
91 final Bundle bundle = (Bundle) msg.obj; | 77 final Bundle bundle = (Bundle) msg.obj; |
92 String account = mGsaHelper.getGSAAccountFromState(bundle.getByteArr
ay(KEY_GSA_STATE)); | 78 String account = mGsaHelper.getGSAAccountFromState(bundle.getByteArr
ay(KEY_GSA_STATE)); |
93 RecordHistogram.recordEnumeratedHistogram(ACCOUNT_CHANGE_HISTOGRAM, | 79 RecordHistogram.recordEnumeratedHistogram(ACCOUNT_CHANGE_HISTOGRAM, |
94 ACCOUNT_CHANGE_SOURCE_SERVICE, ACCOUNT_CHANGE_SOURCE_COUNT); | 80 ACCOUNT_CHANGE_SOURCE_SERVICE, ACCOUNT_CHANGE_SOURCE_COUNT); |
95 GSAState.getInstance(mContext.getApplicationContext()).setGsaAccount
(account); | 81 GSAState.getInstance(mContext).setGsaAccount(account); |
96 if (sHasRecordedPss) { | 82 if (mOnMessageReceived != null) mOnMessageReceived.onResult(bundle); |
97 if (mOnMessageReceived != null) mOnMessageReceived.onResult(bund
le); | |
98 return; | |
99 } | |
100 | |
101 // Getting the PSS for the GSA service process can be long, don't bl
ock the UI thread on | |
102 // that. Also, don't process the callback before the PSS is known, s
ince the callback | |
103 // can lead to a service disconnect, which can lead to the framework
killing the | |
104 // process. Hence an AsyncTask (long operation), and processing the
callback in | |
105 // onPostExecute() (don't disconnect before). | |
106 sHasRecordedPss = true; | |
107 new AsyncTask<Void, Void, Integer>() { | |
108 @Override | |
109 protected Integer doInBackground(Void... params) { | |
110 TraceEvent.begin("GSAServiceClient.getPssForservice"); | |
111 try { | |
112 // Looking for the service process is done by component
name, which is | |
113 // inefficient. We really want the PID, which is only ac
cessible from within | |
114 // a Binder transaction. Since the service connection is
Messenger-based, | |
115 // the calls are not processed from a Binder thread. The
alternatives are: | |
116 // 1. Override methods in the framework to append the ca
lling PID to the | |
117 // Message. | |
118 // 2. Usse msg.callingUid to narrow down the search. | |
119 // | |
120 // (1) is dirty (and brittle), and (2) only works on L+,
and still requires | |
121 // to get the full list of services from ActivityManager
. | |
122 return getPssForService(mComponentName); | |
123 } finally { | |
124 TraceEvent.end("GSAServiceClient.getPssForservice"); | |
125 } | |
126 } | |
127 | |
128 @Override | |
129 protected void onPostExecute(Integer pssInKB) { | |
130 if (pssInKB != INVALID_PSS) { | |
131 RecordHistogram.recordMemoryKBHistogram( | |
132 "Search.GsaProcessMemoryPss", pssInKB); | |
133 } | |
134 if (mOnMessageReceived != null) mOnMessageReceived.onResult(
bundle); | |
135 } | |
136 }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); | |
137 } | 83 } |
138 } | 84 } |
139 | 85 |
140 /** | 86 /** |
141 * Get the PSS used by the process hosting a service. | |
142 * | |
143 * @param packageName Package name of the service to search for. | |
144 * @return the PSS in kB of the process hosting a service, or INVALID_PSS. | |
145 */ | |
146 @VisibleForTesting | |
147 static int getPssForService(ComponentName componentName) { | |
148 if (componentName == null) return INVALID_PSS; | |
149 Context context = ContextUtils.getApplicationContext(); | |
150 ActivityManager activityManager = | |
151 (ActivityManager) context.getSystemService(Context.ACTIVITY_SERV
ICE); | |
152 List<ActivityManager.RunningServiceInfo> services = | |
153 activityManager.getRunningServices(1000); | |
154 if (services == null) return INVALID_PSS; | |
155 int pid = -1; | |
156 for (ActivityManager.RunningServiceInfo info : services) { | |
157 if (componentName.equals(info.service)) { | |
158 pid = info.pid; | |
159 break; | |
160 } | |
161 } | |
162 if (pid == -1) return INVALID_PSS; | |
163 Debug.MemoryInfo infos[] = activityManager.getProcessMemoryInfo(new int[
] {pid}); | |
164 if (infos == null || infos.length == 0) return INVALID_PSS; | |
165 return infos[0].getTotalPss(); | |
166 } | |
167 | |
168 /** | |
169 * Constructs an instance of this class. | 87 * Constructs an instance of this class. |
170 * | 88 * |
171 * @param context Appliation context. | 89 * @param context Appliation context. |
172 * @param onMessageReceived optional callback when a message is received. | 90 * @param onMessageReceived optional callback when a message is received. |
173 */ | 91 */ |
174 GSAServiceClient(Context context, Callback<Bundle> onMessageReceived) { | 92 GSAServiceClient(Context context, Callback<Bundle> onMessageReceived) { |
175 mContext = context.getApplicationContext(); | 93 mContext = context.getApplicationContext(); |
176 mOnMessageReceived = onMessageReceived; | 94 mOnMessageReceived = onMessageReceived; |
177 mHandler = new IncomingHandler(); | 95 mHandler = new IncomingHandler(); |
178 mMessenger = new Messenger(mHandler); | 96 mMessenger = new Messenger(mHandler); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 public void onServiceDisconnected(ComponentName name) { | 147 public void onServiceDisconnected(ComponentName name) { |
230 mService = null; | 148 mService = null; |
231 } | 149 } |
232 | 150 |
233 @Override | 151 @Override |
234 public void onServiceConnected(ComponentName name, IBinder service) { | 152 public void onServiceConnected(ComponentName name, IBinder service) { |
235 // Ignore this call if we disconnected in the meantime. | 153 // Ignore this call if we disconnected in the meantime. |
236 if (mContext == null) return; | 154 if (mContext == null) return; |
237 | 155 |
238 mService = new Messenger(service); | 156 mService = new Messenger(service); |
239 mComponentName = name; | |
240 try { | 157 try { |
241 Message registerClientMessage = Message.obtain( | 158 Message registerClientMessage = Message.obtain( |
242 null, REQUEST_REGISTER_CLIENT); | 159 null, REQUEST_REGISTER_CLIENT); |
243 registerClientMessage.replyTo = mMessenger; | 160 registerClientMessage.replyTo = mMessenger; |
244 Bundle b = mGsaHelper.getBundleForRegisteringGSAClient(mContext)
; | 161 Bundle b = mGsaHelper.getBundleForRegisteringGSAClient(mContext)
; |
245 if (b == null) b = new Bundle(); | 162 if (b == null) b = new Bundle(); |
246 b.putString(KEY_GSA_PACKAGE_NAME, mContext.getPackageName()); | 163 b.putString(KEY_GSA_PACKAGE_NAME, mContext.getPackageName()); |
247 b.putBoolean(KEY_GSA_SUPPORTS_BROADCAST, | 164 b.putBoolean(KEY_GSA_SUPPORTS_BROADCAST, |
248 GSAAccountChangeListener.holdsAccountUpdatePermission())
; | 165 GSAAccountChangeListener.holdsAccountUpdatePermission())
; |
249 registerClientMessage.setData(b); | 166 registerClientMessage.setData(b); |
250 mService.send(registerClientMessage); | 167 mService.send(registerClientMessage); |
251 // Send prepare overlay message if there is a pending GSA contex
t. | 168 // Send prepare overlay message if there is a pending GSA contex
t. |
252 } catch (RemoteException e) { | 169 } catch (RemoteException e) { |
253 Log.w(SERVICE_CONNECTION_TAG, "GSAServiceConnection - remote cal
l failed", e); | 170 Log.w(SERVICE_CONNECTION_TAG, "GSAServiceConnection - remote cal
l failed", e); |
254 } | 171 } |
255 } | 172 } |
256 } | 173 } |
257 } | 174 } |
OLD | NEW |