| Index: chrome/android/java/src/org/chromium/chrome/browser/gsa/GSAServiceClient.java
|
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gsa/GSAServiceClient.java b/chrome/android/java/src/org/chromium/chrome/browser/gsa/GSAServiceClient.java
|
| index 688c52f1268a996ef84465233481a02cc5a1d19a..b82a90998561d7e422b5b8532f541162d7d85df6 100644
|
| --- a/chrome/android/java/src/org/chromium/chrome/browser/gsa/GSAServiceClient.java
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/gsa/GSAServiceClient.java
|
| @@ -5,11 +5,14 @@
|
| package org.chromium.chrome.browser.gsa;
|
|
|
| import android.annotation.SuppressLint;
|
| +import android.app.ActivityManager;
|
| import android.content.ComponentName;
|
| import android.content.Context;
|
| import android.content.Intent;
|
| import android.content.ServiceConnection;
|
| +import android.os.AsyncTask;
|
| import android.os.Bundle;
|
| +import android.os.Debug;
|
| import android.os.Handler;
|
| import android.os.IBinder;
|
| import android.os.Message;
|
| @@ -18,9 +21,15 @@ import android.os.RemoteException;
|
| import android.util.Log;
|
|
|
| import org.chromium.base.Callback;
|
| +import org.chromium.base.ContextUtils;
|
| +import org.chromium.base.TraceEvent;
|
| +import org.chromium.base.VisibleForTesting;
|
| import org.chromium.base.annotations.SuppressFBWarnings;
|
| +import org.chromium.base.metrics.RecordHistogram;
|
| import org.chromium.chrome.browser.ChromeApplication;
|
|
|
| +import java.util.List;
|
| +
|
| /**
|
| * A simple client that connects and talks to the GSAService using Messages.
|
| */
|
| @@ -31,8 +40,8 @@ public class GSAServiceClient {
|
| * Constants for gsa communication. These should not change without corresponding changes on the
|
| * service side in GSA.
|
| */
|
| - private static final String GSA_SERVICE =
|
| - "com.google.android.ssb.action.SSB_SERVICE";
|
| + @VisibleForTesting
|
| + static final String GSA_SERVICE = "com.google.android.ssb.action.SSB_SERVICE";
|
| public static final int REQUEST_REGISTER_CLIENT = 2;
|
| public static final int RESPONSE_UPDATE_SSB = 3;
|
|
|
| @@ -40,6 +49,10 @@ public class GSAServiceClient {
|
| public static final String KEY_GSA_CONTEXT = "ssb_service:ssb_context";
|
| public static final String KEY_GSA_PACKAGE_NAME = "ssb_service:ssb_package_name";
|
|
|
| + @VisibleForTesting
|
| + static final int INVALID_PSS = -1;
|
| +
|
| + private static boolean sHasRecordedPss;
|
| /** Messenger to handle incoming messages from the service */
|
| private final Messenger mMessenger;
|
| private final IncomingHandler mHandler;
|
| @@ -50,7 +63,7 @@ public class GSAServiceClient {
|
|
|
| /** Messenger for communicating with service. */
|
| private Messenger mService;
|
| -
|
| + private ComponentName mComponentName;
|
|
|
| /**
|
| * Handler of incoming messages from service.
|
| @@ -60,17 +73,85 @@ public class GSAServiceClient {
|
| private class IncomingHandler extends Handler {
|
| @Override
|
| public void handleMessage(Message msg) {
|
| - if (msg.what == RESPONSE_UPDATE_SSB) {
|
| - if (mService == null) return;
|
| - Bundle bundle = (Bundle) msg.obj;
|
| - String account =
|
| - mGsaHelper.getGSAAccountFromState(bundle.getByteArray(KEY_GSA_STATE));
|
| - GSAState.getInstance(mContext.getApplicationContext()).setGsaAccount(account);
|
| - if (mOnMessageReceived != null) mOnMessageReceived.onResult(bundle);
|
| - } else {
|
| + if (msg.what != RESPONSE_UPDATE_SSB) {
|
| super.handleMessage(msg);
|
| + return;
|
| + }
|
| +
|
| + if (mService == null) return;
|
| + final Bundle bundle = (Bundle) msg.obj;
|
| + String account = mGsaHelper.getGSAAccountFromState(bundle.getByteArray(KEY_GSA_STATE));
|
| + GSAState.getInstance(mContext.getApplicationContext()).setGsaAccount(account);
|
| + if (sHasRecordedPss) {
|
| + if (mOnMessageReceived != null) mOnMessageReceived.onResult(bundle);
|
| + return;
|
| + }
|
| +
|
| + // Getting the PSS for the GSA service process can be long, don't block the UI thread on
|
| + // that. Also, don't process the callback before the PSS is known, since the callback
|
| + // can lead to a service disconnect, which can lead to the framework killing the
|
| + // process. Hence an AsyncTask (long operation), and processing the callback in
|
| + // onPostExecute() (don't disconnect before).
|
| + sHasRecordedPss = true;
|
| + new AsyncTask<Void, Void, Integer>() {
|
| + @Override
|
| + protected Integer doInBackground(Void... params) {
|
| + TraceEvent.begin("GSAServiceClient.getPssForservice");
|
| + try {
|
| + // Looking for the service process is done by component name, which is
|
| + // inefficient. We really want the PID, which is only accessible from within
|
| + // a Binder transaction. Since the service connection is Messenger-based,
|
| + // the calls are not processed from a Binder thread. The alternatives are:
|
| + // 1. Override methods in the framework to append the calling PID to the
|
| + // Message.
|
| + // 2. Usse msg.callingUid to narrow down the search.
|
| + //
|
| + // (1) is dirty (and brittle), and (2) only works on L+, and still requires
|
| + // to get the full list of services from ActivityManager.
|
| + return getPssForService(mComponentName);
|
| + } finally {
|
| + TraceEvent.end("GSAServiceClient.getPssForservice");
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + protected void onPostExecute(Integer pssInKB) {
|
| + if (pssInKB != INVALID_PSS) {
|
| + RecordHistogram.recordMemoryKBHistogram(
|
| + "Search.GsaProcessMemoryPss", pssInKB);
|
| + }
|
| + if (mOnMessageReceived != null) mOnMessageReceived.onResult(bundle);
|
| + }
|
| + }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Get the PSS used by the process hosting a service.
|
| + *
|
| + * @param packageName Package name of the service to search for.
|
| + * @return the PSS in kB of the process hosting a service, or INVALID_PSS.
|
| + */
|
| + @VisibleForTesting
|
| + static int getPssForService(ComponentName componentName) {
|
| + if (componentName == null) return INVALID_PSS;
|
| + Context context = ContextUtils.getApplicationContext();
|
| + ActivityManager activityManager =
|
| + (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
| + List<ActivityManager.RunningServiceInfo> services =
|
| + activityManager.getRunningServices(1000);
|
| + if (services == null) return INVALID_PSS;
|
| + int pid = -1;
|
| + for (ActivityManager.RunningServiceInfo info : services) {
|
| + if (componentName.equals(info.service)) {
|
| + pid = info.pid;
|
| + break;
|
| }
|
| }
|
| + if (pid == -1) return INVALID_PSS;
|
| + Debug.MemoryInfo infos[] = activityManager.getProcessMemoryInfo(new int[] {pid});
|
| + if (infos == null || infos.length == 0) return INVALID_PSS;
|
| + return infos[0].getTotalPss();
|
| }
|
|
|
| /**
|
| @@ -137,6 +218,7 @@ public class GSAServiceClient {
|
| if (mContext == null) return;
|
|
|
| mService = new Messenger(service);
|
| + mComponentName = name;
|
| try {
|
| Message registerClientMessage = Message.obtain(
|
| null, REQUEST_REGISTER_CLIENT);
|
|
|