• 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(
35             Context context,
36             Intent bindIntent,
37             int bindFlags,
38             Handler handler,
39             Executor executor,
40             ChildServiceConnectionDelegate delegate,
41             String instanceName) {
42         mContext = context;
43         mBindIntent = bindIntent;
44         mBindFlags = bindFlags;
45         mHandler = handler;
46         mExecutor = executor;
47         mDelegate = delegate;
48         mInstanceName = instanceName;
49     }
50 
51     @Override
bindServiceConnection()52     public boolean bindServiceConnection() {
53         try {
54             TraceEvent.begin("ChildServiceConnectionImpl.bindServiceConnection");
55             mBound =
56                     BindService.doBindService(
57                             mContext,
58                             mBindIntent,
59                             this,
60                             mBindFlags,
61                             mHandler,
62                             mExecutor,
63                             mInstanceName);
64         } finally {
65             TraceEvent.end("ChildServiceConnectionImpl.bindServiceConnection");
66         }
67         return mBound;
68     }
69 
70     @Override
unbindServiceConnection()71     public void unbindServiceConnection() {
72         if (mBound) {
73             mContext.unbindService(this);
74             mBound = false;
75         }
76     }
77 
78     @Override
isBound()79     public boolean isBound() {
80         return mBound;
81     }
82 
83     @Override
updateGroupImportance(int group, int importanceInGroup)84     public void updateGroupImportance(int group, int importanceInGroup) {
85         // ChildProcessConnection checks there is a real connection to the service before calling
86         // this, and this `isBound` check should in theory be unnecessary. However this is still
87         // tripped on some devices where another service connection bound successfully but this
88         // service connection failed in `bindServiceConnection`. Such a case is not expected OS
89         // behavior and is not handled. However, avoid crashing in `updateServiceGroup` by doing
90         // this check here.
91         if (!isBound()) {
92             return;
93         }
94         if (BindService.supportVariableConnections()) {
95             try {
96                 ApiHelperForQ.updateServiceGroup(mContext, this, group, importanceInGroup);
97             } catch (IllegalArgumentException e) {
98                 // There is an unavoidable race here binding might be removed for example due to a
99                 // crash, which has not been processed on the launcher thread.
100                 // Ignore these. See crbug.com/1026626 and crbug.com/1026626 for context.
101                 return;
102             }
103             BindService.doBindService(
104                     mContext, mBindIntent, this, mBindFlags, mHandler, mExecutor, mInstanceName);
105         }
106     }
107 
108     @Override
retire()109     public void retire() {
110         mDelegate = null;
111         unbindServiceConnection();
112     }
113 
114     @Override
onServiceConnected(ComponentName className, final IBinder service)115     public void onServiceConnected(ComponentName className, final IBinder service) {
116         if (mDelegate == null) {
117             Log.w(TAG, "onServiceConnected after timeout " + className);
118             return;
119         }
120         mDelegate.onServiceConnected(service);
121     }
122 
123     // Called on the main thread to notify that the child service did not disconnect gracefully.
124     @Override
onServiceDisconnected(ComponentName className)125     public void onServiceDisconnected(ComponentName className) {
126         if (mDelegate != null) mDelegate.onServiceDisconnected();
127     }
128 }
129