1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.stubs.am; 18 19 import static com.android.frameworks.perftests.am.util.Constants.COMMAND_ACQUIRE_CONTENT_PROVIDER; 20 import static com.android.frameworks.perftests.am.util.Constants.COMMAND_BIND_SERVICE; 21 import static com.android.frameworks.perftests.am.util.Constants.COMMAND_RELEASE_CONTENT_PROVIDER; 22 import static com.android.frameworks.perftests.am.util.Constants.COMMAND_SEND_BROADCAST; 23 import static com.android.frameworks.perftests.am.util.Constants.COMMAND_START_ACTIVITY; 24 import static com.android.frameworks.perftests.am.util.Constants.COMMAND_STOP_ACTIVITY; 25 import static com.android.frameworks.perftests.am.util.Constants.COMMAND_UNBIND_SERVICE; 26 27 import android.app.Service; 28 import android.content.BroadcastReceiver; 29 import android.content.ComponentName; 30 import android.content.ContentResolver; 31 import android.content.Context; 32 import android.content.IContentProvider; 33 import android.content.Intent; 34 import android.content.ServiceConnection; 35 import android.net.Uri; 36 import android.os.Binder; 37 import android.os.Bundle; 38 import android.os.Handler; 39 import android.os.HandlerThread; 40 import android.os.IBinder; 41 import android.os.Looper; 42 import android.os.Message; 43 import android.os.Messenger; 44 import android.os.RemoteException; 45 import android.util.ArrayMap; 46 import android.util.Log; 47 48 import com.android.frameworks.perftests.am.util.Constants; 49 import com.android.frameworks.perftests.am.util.ICommandReceiver; 50 51 public class InitService extends Service { 52 private static final String TAG = "InitService"; 53 public static final boolean VERBOSE = false; 54 55 private static class Stub extends ICommandReceiver.Stub { 56 private final Context mContext; 57 private final Messenger mCallback; 58 private final Handler mHandler; 59 private final Messenger mMessenger; 60 final ArrayMap<String, MyServiceConnection> mServices = 61 new ArrayMap<String, MyServiceConnection>(); 62 final ArrayMap<Uri, IContentProvider> mProviders = 63 new ArrayMap<Uri, IContentProvider>(); 64 Stub(Context context, Messenger callback)65 Stub(Context context, Messenger callback) { 66 mContext = context; 67 mCallback = callback; 68 HandlerThread thread = new HandlerThread("result handler"); 69 thread.start(); 70 mHandler = new H(thread.getLooper()); 71 mMessenger = new Messenger(mHandler); 72 } 73 74 private class H extends Handler { H(Looper looper)75 H(Looper looper) { 76 super(looper); 77 } 78 79 @Override handleMessage(Message msg)80 public void handleMessage(Message msg) { 81 if (msg.what == Constants.MSG_DEFAULT) { 82 if (VERBOSE) { 83 Log.i(TAG, "H: received seq=" + msg.arg1 + ", result=" + msg.arg2); 84 } 85 sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, msg.arg1, msg.arg2, null); 86 } else if (msg.what == Constants.MSG_UNBIND_DONE) { 87 if (VERBOSE) { 88 Log.i(TAG, "H: received unbind=" + msg.obj); 89 } 90 synchronized (InitService.sStub) { 91 Bundle b = (Bundle) msg.obj; 92 String pkg = b.getString(Constants.EXTRA_SOURCE_PACKAGE, ""); 93 MyServiceConnection c = mServices.remove(pkg); 94 if (c != null) { 95 sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, c.mSeq, 96 Constants.RESULT_NO_ERROR, null); 97 } 98 } 99 } 100 } 101 } 102 103 @Override sendCommand(int command, int seq, String sourcePackage, String targetPackage, int flags, Bundle bundle)104 public void sendCommand(int command, int seq, String sourcePackage, String targetPackage, 105 int flags, Bundle bundle) { 106 if (VERBOSE) { 107 Log.i(TAG, "Received command=" + command + ", seq=" + seq + ", from=" 108 + sourcePackage + ", to=" + targetPackage + ", flags=" + flags); 109 } 110 switch (command) { 111 case COMMAND_BIND_SERVICE: 112 handleBindService(seq, targetPackage, flags, bundle); 113 break; 114 case COMMAND_UNBIND_SERVICE: 115 handleUnbindService(seq, targetPackage); 116 break; 117 case COMMAND_ACQUIRE_CONTENT_PROVIDER: 118 acquireProvider(seq, bundle.getParcelable(Constants.EXTRA_URI)); 119 break; 120 case COMMAND_RELEASE_CONTENT_PROVIDER: 121 releaseProvider(seq, bundle.getParcelable(Constants.EXTRA_URI)); 122 break; 123 case COMMAND_SEND_BROADCAST: 124 sendBroadcast(seq, targetPackage); 125 break; 126 case COMMAND_START_ACTIVITY: 127 startActivity(seq, targetPackage); 128 break; 129 case COMMAND_STOP_ACTIVITY: 130 stopActivity(seq, targetPackage); 131 break; 132 } 133 } 134 handleBindService(int seq, String targetPackage, int flags, Bundle bundle)135 private void handleBindService(int seq, String targetPackage, int flags, Bundle bundle) { 136 Intent intent = new Intent(); 137 intent.setClassName(targetPackage, "com.android.stubs.am.TestService"); 138 intent.putExtra(Constants.EXTRA_RECEIVER_CALLBACK, mMessenger); 139 if (bundle != null) { 140 intent.putExtras(bundle); 141 } 142 synchronized (this) { 143 if (!mServices.containsKey(targetPackage)) { 144 MyServiceConnection c = new MyServiceConnection(mCallback); 145 c.mSeq = seq; 146 if (!mContext.bindService(intent, c, flags)) { 147 Log.e(TAG, "Unable to bind to service in " + targetPackage); 148 sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq, 149 Constants.RESULT_ERROR, null); 150 } else { 151 if (VERBOSE) { 152 Log.i(TAG, "Bind to service " + intent); 153 } 154 mServices.put(targetPackage, c); 155 } 156 } else { 157 sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq, 158 Constants.RESULT_NO_ERROR, null); 159 } 160 } 161 } 162 handleUnbindService(int seq, String target)163 private void handleUnbindService(int seq, String target) { 164 MyServiceConnection c = null; 165 synchronized (this) { 166 c = mServices.get(target); 167 } 168 if (c != null) { 169 c.mSeq = seq; 170 mContext.unbindService(c); 171 } 172 } 173 acquireProvider(int seq, Uri uri)174 private void acquireProvider(int seq, Uri uri) { 175 ContentResolver resolver = mContext.getContentResolver(); 176 IContentProvider provider = resolver.acquireProvider(uri); 177 if (provider != null) { 178 synchronized (mProviders) { 179 mProviders.put(uri, provider); 180 } 181 sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq, 182 Constants.RESULT_NO_ERROR, null); 183 } else { 184 sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq, 185 Constants.RESULT_ERROR, null); 186 } 187 } 188 releaseProvider(int seq, Uri uri)189 private void releaseProvider(int seq, Uri uri) { 190 ContentResolver resolver = mContext.getContentResolver(); 191 IContentProvider provider; 192 synchronized (mProviders) { 193 provider = mProviders.get(uri); 194 } 195 if (provider != null) { 196 resolver.releaseProvider(provider); 197 synchronized (mProviders) { 198 mProviders.remove(uri); 199 } 200 } 201 sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq, 202 Constants.RESULT_NO_ERROR, null); 203 } 204 sendBroadcast(final int seq, String targetPackage)205 private void sendBroadcast(final int seq, String targetPackage) { 206 Intent intent = new Intent(Constants.STUB_ACTION_BROADCAST); 207 intent.setPackage(targetPackage); 208 mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() { 209 @Override 210 public void onReceive(Context context, Intent intent) { 211 sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, seq, 212 Constants.RESULT_NO_ERROR, null); 213 } 214 }, null, 0, null, null); 215 } 216 startActivity(int seq, String targetPackage)217 private void startActivity(int seq, String targetPackage) { 218 Intent intent = new Intent(Constants.STUB_ACTION_ACTIVITY); 219 intent.setClassName(targetPackage, "com.android.stubs.am.TestActivity"); 220 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); 221 intent.putExtra(Constants.EXTRA_ARG1, seq); 222 intent.putExtra(Constants.EXTRA_RECEIVER_CALLBACK, mMessenger); 223 mContext.startActivity(intent); 224 } 225 stopActivity(int seq, String targetPackage)226 private void stopActivity(int seq, String targetPackage) { 227 Intent intent = new Intent(Constants.STUB_ACTION_ACTIVITY); 228 intent.setClassName(targetPackage, "com.android.stubs.am.TestActivity"); 229 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); 230 intent.putExtra(Constants.EXTRA_REQ_FINISH_ACTIVITY, true); 231 intent.putExtra(Constants.EXTRA_ARG1, seq); 232 intent.putExtra(Constants.EXTRA_RECEIVER_CALLBACK, mMessenger); 233 mContext.startActivity(intent); 234 } 235 }; 236 sendResult(Messenger callback, int what, int seq, int result, Object obj)237 private static void sendResult(Messenger callback, int what, int seq, int result, Object obj) { 238 Message msg = Message.obtain(); 239 msg.what = what; 240 msg.arg1 = seq; 241 msg.arg2 = result; 242 msg.obj = obj; 243 try { 244 if (VERBOSE) { 245 Log.i(TAG, "Sending result seq=" + seq + ", result=" + result); 246 } 247 callback.send(msg); 248 } catch (RemoteException e) { 249 Log.e(TAG, "Error in sending result back", e); 250 } 251 msg.recycle(); 252 } 253 254 private static class MyServiceConnection implements ServiceConnection { 255 private Messenger mCallback; 256 int mSeq; 257 MyServiceConnection(Messenger callback)258 MyServiceConnection(Messenger callback) { 259 mCallback = callback; 260 } 261 262 @Override onServiceConnected(ComponentName name, IBinder service)263 public void onServiceConnected(ComponentName name, IBinder service) { 264 sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, mSeq, 265 Constants.RESULT_NO_ERROR, null); 266 } 267 268 @Override onServiceDisconnected(ComponentName name)269 public void onServiceDisconnected(ComponentName name) { 270 synchronized (sStub) { 271 MyServiceConnection c = sStub.mServices.remove(name.getPackageName()); 272 if (c != null) { 273 sendResult(mCallback, Constants.REPLY_COMMAND_RESULT, c.mSeq, 274 Constants.RESULT_NO_ERROR, null); 275 } 276 } 277 } 278 } 279 280 private static Stub sStub = null; 281 282 @Override onBind(Intent intent)283 public IBinder onBind(Intent intent) { 284 return new Binder(); 285 } 286 287 @Override onStartCommand(Intent intent, int flags, int startId)288 public int onStartCommand(Intent intent, int flags, int startId) { 289 Messenger callback = intent.getParcelableExtra(Constants.EXTRA_RECEIVER_CALLBACK); 290 if (sStub == null) { 291 sStub = new Stub(getApplicationContext(), callback); 292 } 293 294 Bundle extras = new Bundle(); 295 extras.putString(Constants.EXTRA_SOURCE_PACKAGE, getPackageName()); 296 extras.putBinder(Constants.EXTRA_RECEIVER_CALLBACK, sStub); 297 sendResult(callback, Constants.REPLY_PACKAGE_START_RESULT, 298 intent.getIntExtra(Constants.EXTRA_SEQ, -1), 0, extras); 299 return START_NOT_STICKY; 300 } 301 } 302