• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium Authors
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.base.process_launcher;
6 
7 import android.content.ComponentName;
8 import android.content.Context;
9 import android.content.Intent;
10 import android.content.ServiceConnection;
11 import android.os.Handler;
12 import android.os.IBinder;
13 
14 import org.chromium.base.Log;
15 import org.chromium.base.TraceEvent;
16 import org.chromium.base.compat.ApiHelperForQ;
17 
18 import java.util.concurrent.Executor;
19 
20 /** Implementation of ChildServiceConnection that does connect to a service. */
21 /* package */ class ChildServiceConnectionImpl
22         implements ChildServiceConnection, ServiceConnection {
23     private static final String TAG = "ChildServiceConn";
24 
25     private final Context mContext;
26     private final Intent mBindIntent;
27     private final int mBindFlags;
28     private final Handler mHandler;
29     private final Executor mExecutor;
30     private ChildServiceConnectionDelegate mDelegate;
31     private final String mInstanceName;
32     private boolean mBound;
33 
ChildServiceConnectionImpl(Context context, Intent bindIntent, int bindFlags, Handler handler, Executor executor, ChildServiceConnectionDelegate delegate, String instanceName)34     /* package */ ChildServiceConnectionImpl(Context context, Intent bindIntent, int bindFlags,
35             Handler handler, Executor executor, ChildServiceConnectionDelegate delegate,
36             String instanceName) {
37         mContext = context;
38         mBindIntent = bindIntent;
39         mBindFlags = bindFlags;
40         mHandler = handler;
41         mExecutor = executor;
42         mDelegate = delegate;
43         mInstanceName = instanceName;
44     }
45 
46     @Override
bindServiceConnection()47     public boolean bindServiceConnection() {
48         try {
49             TraceEvent.begin("ChildServiceConnectionImpl.bindServiceConnection");
50             mBound = BindService.doBindService(
51                     mContext, mBindIntent, this, mBindFlags, mHandler, mExecutor, mInstanceName);
52         } finally {
53             TraceEvent.end("ChildServiceConnectionImpl.bindServiceConnection");
54         }
55         return mBound;
56     }
57 
58     @Override
unbindServiceConnection()59     public void unbindServiceConnection() {
60         if (mBound) {
61             mContext.unbindService(this);
62             mBound = false;
63         }
64     }
65 
66     @Override
isBound()67     public boolean isBound() {
68         return mBound;
69     }
70 
71     @Override
updateGroupImportance(int group, int importanceInGroup)72     public void updateGroupImportance(int group, int importanceInGroup) {
73         // ChildProcessConnection checks there is a real connection to the service before calling
74         // this, and this `isBound` check should in theory be unnecessary. However this is still
75         // tripped on some devices where another service connection bound successfully but this
76         // service connection failed in `bindServiceConnection`. Such a case is not expected OS
77         // behavior and is not handled. However, avoid crashing in `updateServiceGroup` by doing
78         // this check here.
79         if (!isBound()) {
80             return;
81         }
82         if (BindService.supportVariableConnections()) {
83             try {
84                 ApiHelperForQ.updateServiceGroup(mContext, this, group, importanceInGroup);
85             } catch (IllegalArgumentException e) {
86                 // There is an unavoidable race here binding might be removed for example due to a
87                 // crash, which has not been processed on the launcher thread.
88                 // Ignore these. See crbug.com/1026626 and crbug.com/1026626 for context.
89                 return;
90             }
91             BindService.doBindService(
92                     mContext, mBindIntent, this, mBindFlags, mHandler, mExecutor, mInstanceName);
93         }
94     }
95 
96     @Override
retire()97     public void retire() {
98         mDelegate = null;
99         unbindServiceConnection();
100     }
101 
102     @Override
onServiceConnected(ComponentName className, final IBinder service)103     public void onServiceConnected(ComponentName className, final IBinder service) {
104         if (mDelegate == null) {
105             Log.w(TAG, "onServiceConnected after timeout " + className);
106             return;
107         }
108         mDelegate.onServiceConnected(service);
109     }
110 
111     // Called on the main thread to notify that the child service did not disconnect gracefully.
112     @Override
onServiceDisconnected(ComponentName className)113     public void onServiceDisconnected(ComponentName className) {
114         if (mDelegate != null) mDelegate.onServiceDisconnected();
115     }
116 }
117