package com.lody.virtual.server.am; import android.app.ActivityManager; import android.app.IServiceConnection; import android.app.IStopUserCallback; import android.app.Notification; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; import android.content.pm.ServiceInfo; import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.IInterface; import android.os.Parcel; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import com.lody.virtual.client.IVClient; import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.env.SpecialComponentList; import com.lody.virtual.client.ipc.ProviderCall; import com.lody.virtual.client.stub.StubManifest; import com.lody.virtual.helper.collection.ArrayMap; import com.lody.virtual.helper.collection.SparseArray; import com.lody.virtual.helper.compat.ActivityManagerCompat; import com.lody.virtual.helper.compat.ApplicationThreadCompat; import com.lody.virtual.helper.compat.BundleCompat; import com.lody.virtual.helper.compat.IApplicationThreadCompat; import com.lody.virtual.helper.utils.ComponentUtils; import com.lody.virtual.helper.utils.VLog; import com.lody.virtual.os.VBinder; import com.lody.virtual.os.VUserHandle; import com.lody.virtual.remote.AppTaskInfo; import com.lody.virtual.remote.PendingIntentData; import com.lody.virtual.remote.PendingResultData; import com.lody.virtual.remote.VParceledListSlice; import com.lody.virtual.server.IActivityManager; import com.lody.virtual.server.interfaces.IProcessObserver; import com.lody.virtual.server.pm.PackageCacheManager; import com.lody.virtual.server.pm.PackageSetting; import com.lody.virtual.server.pm.VAppManagerService; import com.lody.virtual.server.pm.VPackageManagerService; import com.lody.virtual.server.secondary.BinderDelegateService; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import java.util.concurrent.atomic.AtomicReference; import static android.os.Process.killProcess; import static com.lody.virtual.os.VUserHandle.getUserId; /** * @author Lody */ public class VActivityManagerService extends IActivityManager.Stub { private static final boolean BROADCAST_NOT_STARTED_PKG = true; private static final AtomicReference<VActivityManagerService> sService = new AtomicReference<>(); private static final String TAG = VActivityManagerService.class.getSimpleName(); private final SparseArray<ProcessRecord> mPidsSelfLocked = new SparseArray<ProcessRecord>(); private final ActivityStack mMainStack = new ActivityStack(this); private final List<ServiceRecord> mHistory = new ArrayList<ServiceRecord>(); private final ProcessMap<ProcessRecord> mProcessNames = new ProcessMap<ProcessRecord>(); private final PendingIntents mPendingIntents = new PendingIntents(); private ActivityManager am = (ActivityManager) VirtualCore.get().getContext() .getSystemService(Context.ACTIVITY_SERVICE); public static VActivityManagerService get() { return sService.get(); } public static void systemReady(Context context) { new VActivityManagerService().onCreate(context); } private static ServiceInfo resolveServiceInfo(Intent service, int userId) { if (service != null) { ServiceInfo serviceInfo = VirtualCore.get().resolveServiceInfo(service, userId); if (serviceInfo != null) { return serviceInfo; } } return null; } public void onCreate(Context context) { AttributeCache.init(context); PackageManager pm = context.getPackageManager(); PackageInfo packageInfo = null; try { packageInfo = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES | PackageManager.GET_PROVIDERS | PackageManager.GET_META_DATA); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } if (packageInfo == null) { throw new RuntimeException("Unable to found PackageInfo : " + context.getPackageName()); } sService.set(this); } @Override public int startActivity(Intent intent, ActivityInfo info, IBinder resultTo, Bundle options, String resultWho, int requestCode, int userId) { synchronized (this) { return mMainStack.startActivityLocked(userId, intent, info, resultTo, options, resultWho, requestCode); } } @Override public int startActivities(Intent[] intents, String[] resolvedTypes, IBinder token, Bundle options, int userId) { synchronized (this) { ActivityInfo[] infos = new ActivityInfo[intents.length]; for (int i = 0; i < intents.length; i++) { ActivityInfo ai = VirtualCore.get().resolveActivityInfo(intents[i], userId); if (ai == null) { return ActivityManagerCompat.START_INTENT_NOT_RESOLVED; } infos[i] = ai; } return mMainStack.startActivitiesLocked(userId, intents, infos, resolvedTypes, token, options); } } @Override public String getPackageForIntentSender(IBinder binder) { PendingIntentData data = mPendingIntents.getPendingIntent(binder); if (data != null) { return data.creator; } return null; } @Override public PendingIntentData getPendingIntent(IBinder binder) { return mPendingIntents.getPendingIntent(binder); } @Override public void addPendingIntent(IBinder binder, String creator) { mPendingIntents.addPendingIntent(binder, creator); } @Override public void removePendingIntent(IBinder binder) { mPendingIntents.removePendingIntent(binder); } @Override public int getSystemPid() { return VirtualCore.get().myUid(); } @Override public void onActivityCreated(ComponentName component, ComponentName caller, IBinder token, Intent intent, String affinity, int taskId, int launchMode, int flags) { int pid = Binder.getCallingPid(); ProcessRecord targetApp = findProcessLocked(pid); if (targetApp != null) { mMainStack.onActivityCreated(targetApp, component, caller, token, intent, affinity, taskId, launchMode, flags); } } @Override public void onActivityResumed(int userId, IBinder token) { mMainStack.onActivityResumed(userId, token); } @Override public boolean onActivityDestroyed(int userId, IBinder token) { ActivityRecord r = mMainStack.onActivityDestroyed(userId, token); return r != null; } @Override public AppTaskInfo getTaskInfo(int taskId) { return mMainStack.getTaskInfo(taskId); } @Override public String getPackageForToken(int userId, IBinder token) { return mMainStack.getPackageForToken(userId, token); } @Override public ComponentName getActivityClassForToken(int userId, IBinder token) { return mMainStack.getActivityClassForToken(userId, token); } public void processDead(ProcessRecord record) { synchronized (mHistory) { ListIterator<ServiceRecord> iterator = mHistory.listIterator(); while (iterator.hasNext()) { ServiceRecord r = iterator.next(); if (r.process.pid == record.pid) { iterator.remove(); } } mMainStack.processDied(record); } } @Override public IBinder acquireProviderClient(int userId, ProviderInfo info) { ProcessRecord callerApp; synchronized (mPidsSelfLocked) { callerApp = findProcessLocked(VBinder.getCallingPid()); } if (callerApp == null) { throw new SecurityException("Who are you?"); } String processName = info.processName; ProcessRecord r; synchronized (this) { r = startProcessIfNeedLocked(processName, userId, info.packageName); } if (r != null && r.client.asBinder().isBinderAlive()) { try { return r.client.acquireProviderClient(info); } catch (RemoteException e) { e.printStackTrace(); } } return null; } @Override public ComponentName getCallingActivity(int userId, IBinder token) { return mMainStack.getCallingActivity(userId, token); } @Override public String getCallingPackage(int userId, IBinder token) { return mMainStack.getCallingPackage(userId, token); } @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { try { return super.onTransact(code, data, reply, flags); } catch (Throwable e) { e.printStackTrace(); throw e; } } private void addRecord(ServiceRecord r) { mHistory.add(r); } private ServiceRecord findRecordLocked(int userId, ServiceInfo serviceInfo) { synchronized (mHistory) { for (ServiceRecord r : mHistory) { if (r.process.userId == userId && ComponentUtils.isSameComponent(serviceInfo, r.serviceInfo)) { return r; } } return null; } } private ServiceRecord findRecordLocked(IServiceConnection connection) { synchronized (mHistory) { for (ServiceRecord r : mHistory) { if (r.containConnection(connection)) { return r; } } return null; } } @Override public ComponentName startService(IBinder caller, Intent service, String resolvedType, int userId) { synchronized (this) { return startServiceCommon(service, true, userId); } } private ComponentName startServiceCommon(Intent service, boolean scheduleServiceArgs, int userId) { ServiceInfo serviceInfo = resolveServiceInfo(service, userId); if (serviceInfo == null) { return null; } ProcessRecord targetApp = startProcessIfNeedLocked(ComponentUtils.getProcessName(serviceInfo), userId, serviceInfo.packageName); if (targetApp == null) { VLog.e(TAG, "Unable to start new Process for : " + ComponentUtils.toComponentName(serviceInfo)); return null; } IInterface appThread = targetApp.appThread; ServiceRecord r = findRecordLocked(userId, serviceInfo); if (r == null) { r = new ServiceRecord(); r.startId = 0; r.activeSince = SystemClock.elapsedRealtime(); r.process = targetApp; r.serviceInfo = serviceInfo; try { IApplicationThreadCompat.scheduleCreateService(appThread, r, r.serviceInfo, 0); } catch (RemoteException e) { e.printStackTrace(); } addRecord(r); } r.lastActivityTime = SystemClock.uptimeMillis(); if (scheduleServiceArgs) { r.startId++; boolean taskRemoved = serviceInfo.applicationInfo != null && serviceInfo.applicationInfo.targetSdkVersion < Build.VERSION_CODES.ECLAIR; try { IApplicationThreadCompat.scheduleServiceArgs(appThread, r, taskRemoved, r.startId, 0, service); } catch (RemoteException e) { e.printStackTrace(); } } return ComponentUtils.toComponentName(serviceInfo); } @Override public int stopService(IBinder caller, Intent service, String resolvedType, int userId) { synchronized (this) { ServiceInfo serviceInfo = resolveServiceInfo(service, userId); if (serviceInfo == null) { return 0; } ServiceRecord r = findRecordLocked(userId, serviceInfo); if (r == null) { return 0; } if (r.getClientCount() <= 0) { try { IApplicationThreadCompat.scheduleStopService(r.process.appThread, r); } catch (RemoteException e) { e.printStackTrace(); } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { mHistory.remove(r); } } return 1; } } @Override public boolean stopServiceToken(ComponentName className, IBinder token, int startId, int userId) { synchronized (this) { ServiceRecord r = (ServiceRecord) token; if (r != null && r.startId == startId) { try { IApplicationThreadCompat.scheduleStopService(r.process.appThread, r); } catch (RemoteException e) { e.printStackTrace(); } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { mHistory.remove(r); } return true; } return false; } } @Override public void setServiceForeground(ComponentName className, IBinder token, int id, Notification notification, boolean keepNotification, int userId) { } @Override public int bindService(IBinder caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) { synchronized (this) { ServiceInfo serviceInfo = resolveServiceInfo(service, userId); if (serviceInfo == null) { return 0; } ServiceRecord r = findRecordLocked(userId, serviceInfo); boolean firstLaunch = r == null; if (firstLaunch) { if ((flags & Context.BIND_AUTO_CREATE) != 0) { startServiceCommon(service, false, userId); r = findRecordLocked(userId, serviceInfo); } } if (r == null) { return 0; } ServiceRecord.IntentBindRecord boundRecord = r.peekBinding(service); if (boundRecord != null && boundRecord.binder != null && boundRecord.binder.isBinderAlive()) { if (boundRecord.doRebind) { try { IApplicationThreadCompat.scheduleBindService(r.process.appThread, r, service, true, 0); } catch (RemoteException e) { e.printStackTrace(); } } ComponentName componentName = new ComponentName(r.serviceInfo.packageName, r.serviceInfo.name); connectService(connection, componentName, boundRecord); } else { try { IApplicationThreadCompat.scheduleBindService(r.process.appThread, r, service, false, 0); } catch (RemoteException e) { e.printStackTrace(); } } r.lastActivityTime = SystemClock.uptimeMillis(); r.addToBoundIntent(service, connection); return 1; } } @Override public boolean unbindService(IServiceConnection connection, int userId) { synchronized (this) { ServiceRecord r = findRecordLocked(connection); if (r == null) { return false; } for (ServiceRecord.IntentBindRecord bindRecord : r.bindings) { if (!bindRecord.containConnection(connection)) { continue; } bindRecord.removeConnection(connection); try { IApplicationThreadCompat.scheduleUnbindService(r.process.appThread, r, bindRecord.intent); } catch (RemoteException e) { e.printStackTrace(); } } if (r.startId <= 0 && r.getConnectionCount() <= 0) { try { IApplicationThreadCompat.scheduleStopService(r.process.appThread, r); } catch (RemoteException e) { e.printStackTrace(); } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { mHistory.remove(r); } } return true; } } @Override public void unbindFinished(IBinder token, Intent service, boolean doRebind, int userId) { synchronized (this) { ServiceRecord r = (ServiceRecord) token; if (r != null) { ServiceRecord.IntentBindRecord boundRecord = r.peekBinding(service); if (boundRecord != null) { boundRecord.doRebind = doRebind; } } } } @Override public boolean isVAServiceToken(IBinder token) { return token instanceof ServiceRecord; } @Override public void serviceDoneExecuting(IBinder token, int type, int startId, int res, int userId) { synchronized (this) { ServiceRecord r = (ServiceRecord) token; if (r == null) { return; } if (ActivityManagerCompat.SERVICE_DONE_EXECUTING_STOP == type) { mHistory.remove(r); } } } @Override public IBinder peekService(Intent service, String resolvedType, int userId) { synchronized (this) { ServiceInfo serviceInfo = resolveServiceInfo(service, userId); if (serviceInfo == null) { return null; } ServiceRecord r = findRecordLocked(userId, serviceInfo); if (r != null) { ServiceRecord.IntentBindRecord boundRecord = r.peekBinding(service); if (boundRecord != null) { return boundRecord.binder; } } return null; } } @Override public void publishService(IBinder token, Intent intent, IBinder service, int userId) { synchronized (this) { ServiceRecord r = (ServiceRecord) token; if (r != null) { ServiceRecord.IntentBindRecord boundRecord = r.peekBinding(intent); if (boundRecord != null) { boundRecord.binder = service; for (IServiceConnection conn : boundRecord.connections) { ComponentName component = ComponentUtils.toComponentName(r.serviceInfo); connectService(conn, component, boundRecord); } } } } } private void connectService(IServiceConnection conn, ComponentName component, ServiceRecord.IntentBindRecord r) { try { BinderDelegateService delegateService = new BinderDelegateService(component, r.binder); conn.connected(component, delegateService); } catch (RemoteException e) { e.printStackTrace(); } } @Override public VParceledListSlice<ActivityManager.RunningServiceInfo> getServices(int maxNum, int flags, int userId) { synchronized (mHistory) { List<ActivityManager.RunningServiceInfo> services = new ArrayList<>(mHistory.size()); for (ServiceRecord r : mHistory) { if (r.process.userId != userId) { continue; } ActivityManager.RunningServiceInfo info = new ActivityManager.RunningServiceInfo(); info.uid = r.process.vuid; info.pid = r.process.pid; ProcessRecord processRecord = findProcessLocked(r.process.pid); if (processRecord != null) { info.process = processRecord.processName; info.clientPackage = processRecord.info.packageName; } info.activeSince = r.activeSince; info.lastActivityTime = r.lastActivityTime; info.clientCount = r.getClientCount(); info.service = ComponentUtils.toComponentName(r.serviceInfo); info.started = r.startId > 0; services.add(info); } return new VParceledListSlice<>(services); } } @Override public void processRestarted(String packageName, String processName, int userId) { int callingPid = getCallingPid(); int appId = VAppManagerService.get().getAppId(packageName); int uid = VUserHandle.getUid(userId, appId); synchronized (this) { ProcessRecord app = findProcessLocked(callingPid); if (app == null) { ApplicationInfo appInfo = VPackageManagerService.get().getApplicationInfo(packageName, 0, userId); appInfo.flags |= ApplicationInfo.FLAG_HAS_CODE; String stubProcessName = getProcessName(callingPid); int vpid = parseVPid(stubProcessName); if (vpid != -1) { performStartProcessLocked(uid, vpid, appInfo, processName); } } } } private int parseVPid(String stubProcessName) { String prefix = VirtualCore.get().getHostPkg() + ":p"; if (stubProcessName != null && stubProcessName.startsWith(prefix)) { try { return Integer.parseInt(stubProcessName.substring(prefix.length())); } catch (NumberFormatException e) { e.printStackTrace(); } } return -1; } private String getProcessName(int pid) { for (ActivityManager.RunningAppProcessInfo info : am.getRunningAppProcesses()) { if (info.pid == pid) { return info.processName; } } return null; } private void attachClient(int pid, final IBinder clientBinder) { final IVClient client = IVClient.Stub.asInterface(clientBinder); if (client == null) { killProcess(pid); return; } IInterface thread = null; try { thread = ApplicationThreadCompat.asInterface(client.getAppThread()); } catch (RemoteException e) { // process has dead } if (thread == null) { killProcess(pid); return; } ProcessRecord app = null; try { IBinder token = client.getToken(); if (token instanceof ProcessRecord) { app = (ProcessRecord) token; } } catch (RemoteException e) { // process has dead } if (app == null) { killProcess(pid); return; } try { final ProcessRecord record = app; clientBinder.linkToDeath(new DeathRecipient() { @Override public void binderDied() { clientBinder.unlinkToDeath(this, 0); onProcessDead(record); } }, 0); } catch (RemoteException e) { e.printStackTrace(); } app.client = client; app.appThread = thread; app.pid = pid; synchronized (mProcessNames) { mProcessNames.put(app.processName, app.vuid, app); mPidsSelfLocked.put(app.pid, app); } } private void onProcessDead(ProcessRecord record) { mProcessNames.remove(record.processName, record.vuid); mPidsSelfLocked.remove(record.pid); processDead(record); record.lock.open(); } @Override public int getFreeStubCount() { return StubManifest.STUB_COUNT - mPidsSelfLocked.size(); } @Override public int initProcess(String packageName, String processName, int userId) { synchronized (this) { ProcessRecord r = startProcessIfNeedLocked(processName, userId, packageName); return r != null ? r.vpid : -1; } } ProcessRecord startProcessIfNeedLocked(String processName, int userId, String packageName) { if (VActivityManagerService.get().getFreeStubCount() < 3) { // run GC killAllApps(); } PackageSetting ps = PackageCacheManager.getSetting(packageName); ApplicationInfo info = VPackageManagerService.get().getApplicationInfo(packageName, 0, userId); if (ps == null || info == null) { return null; } if (!ps.isLaunched(userId)) { sendFirstLaunchBroadcast(ps, userId); ps.setLaunched(userId, true); VAppManagerService.get().savePersistenceData(); } int uid = VUserHandle.getUid(userId, ps.appId); ProcessRecord app = mProcessNames.get(processName, uid); if (app != null && app.client.asBinder().isBinderAlive()) { return app; } int vpid = queryFreeStubProcessLocked(); if (vpid == -1) { return null; } app = performStartProcessLocked(uid, vpid, info, processName); if (app != null) { app.pkgList.add(info.packageName); } return app; } private void sendFirstLaunchBroadcast(PackageSetting ps, int userId) { Intent intent = new Intent(Intent.ACTION_PACKAGE_FIRST_LAUNCH, Uri.fromParts("package", ps.packageName, null)); intent.setPackage(ps.packageName); intent.putExtra(Intent.EXTRA_UID, VUserHandle.getUid(ps.appId, userId)); intent.putExtra("android.intent.extra.user_handle", userId); sendBroadcastAsUser(intent, null); } @Override public int getUidByPid(int pid) { synchronized (mPidsSelfLocked) { ProcessRecord r = findProcessLocked(pid); if (r != null) { return r.vuid; } } return Process.myUid(); } private ProcessRecord performStartProcessLocked(int vuid, int vpid, ApplicationInfo info, String processName) { ProcessRecord app = new ProcessRecord(info, processName, vuid, vpid); Bundle extras = new Bundle(); BundleCompat.putBinder(extras, "_VA_|_binder_", app); extras.putInt("_VA_|_vuid_", vuid); extras.putString("_VA_|_process_", processName); extras.putString("_VA_|_pkg_", info.packageName); Bundle res = ProviderCall.call(StubManifest.getStubAuthority(vpid), "_VA_|_init_process_", null, extras); if (res == null) { return null; } int pid = res.getInt("_VA_|_pid_"); IBinder clientBinder = BundleCompat.getBinder(res, "_VA_|_client_"); attachClient(pid, clientBinder); return app; } private int queryFreeStubProcessLocked() { for (int vpid = 0; vpid < StubManifest.STUB_COUNT; vpid++) { int N = mPidsSelfLocked.size(); boolean using = false; while (N-- > 0) { ProcessRecord r = mPidsSelfLocked.valueAt(N); if (r.vpid == vpid) { using = true; break; } } if (using) { continue; } return vpid; } return -1; } @Override public boolean isAppProcess(String processName) { return parseVPid(processName) != -1; } @Override public boolean isAppPid(int pid) { synchronized (mPidsSelfLocked) { return findProcessLocked(pid) != null; } } @Override public String getAppProcessName(int pid) { synchronized (mPidsSelfLocked) { ProcessRecord r = mPidsSelfLocked.get(pid); if (r != null) { return r.processName; } } return null; } @Override public List<String> getProcessPkgList(int pid) { synchronized (mPidsSelfLocked) { ProcessRecord r = mPidsSelfLocked.get(pid); if (r != null) { return new ArrayList<String>(r.pkgList); } } return null; } @Override public void killAllApps() { synchronized (mPidsSelfLocked) { for (int i = 0; i < mPidsSelfLocked.size(); i++) { ProcessRecord r = mPidsSelfLocked.valueAt(i); killProcess(r.pid); } } } @Override public void killAppByPkg(final String pkg, int userId) { synchronized (mProcessNames) { ArrayMap<String, SparseArray<ProcessRecord>> map = mProcessNames.getMap(); int N = map.size(); while (N-- > 0) { SparseArray<ProcessRecord> uids = map.valueAt(N); for (int i = 0; i < uids.size(); i++) { ProcessRecord r = uids.valueAt(i); if (userId != VUserHandle.USER_ALL) { if (r.userId != userId) { continue; } } if (r.pkgList.contains(pkg)) { killProcess(r.pid); } } } } } @Override public boolean isAppRunning(String packageName, int userId) { boolean running = false; synchronized (mPidsSelfLocked) { int N = mPidsSelfLocked.size(); while (N-- > 0) { ProcessRecord r = mPidsSelfLocked.valueAt(N); if (r.userId == userId && r.info.packageName.equals(packageName)) { running = true; break; } } return running; } } @Override public void killApplicationProcess(final String processName, int uid) { synchronized (mProcessNames) { ProcessRecord r = mProcessNames.get(processName, uid); if (r != null) { killProcess(r.pid); } } } @Override public void dump() { } @Override public void registerProcessObserver(IProcessObserver observer) { } @Override public void unregisterProcessObserver(IProcessObserver observer) { } @Override public String getInitialPackage(int pid) { synchronized (mPidsSelfLocked) { ProcessRecord r = mPidsSelfLocked.get(pid); if (r != null) { return r.info.packageName; } return null; } } @Override public void handleApplicationCrash() { // Nothing } @Override public void appDoneExecuting() { synchronized (mPidsSelfLocked) { ProcessRecord r = mPidsSelfLocked.get(VBinder.getCallingPid()); if (r != null) { r.doneExecuting = true; r.lock.open(); } } } /** * Should guard by {@link VActivityManagerService#mPidsSelfLocked} * * @param pid pid */ public ProcessRecord findProcessLocked(int pid) { return mPidsSelfLocked.get(pid); } /** * Should guard by {@link VActivityManagerService#mProcessNames} * * @param uid vuid */ public ProcessRecord findProcessLocked(String processName, int uid) { return mProcessNames.get(processName, uid); } public int stopUser(int userHandle, IStopUserCallback.Stub stub) { synchronized (mPidsSelfLocked) { int N = mPidsSelfLocked.size(); while (N-- > 0) { ProcessRecord r = mPidsSelfLocked.valueAt(N); if (r.userId == userHandle) { killProcess(r.pid); } } } try { stub.userStopped(userHandle); } catch (RemoteException e) { e.printStackTrace(); } return 0; } public void sendOrderedBroadcastAsUser(Intent intent, VUserHandle user, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { Context context = VirtualCore.get().getContext(); if (user != null) { intent.putExtra("_VA_|_user_id_", user.getIdentifier()); } // TODO: checkPermission context.sendOrderedBroadcast(intent, null/* permission */, resultReceiver, scheduler, initialCode, initialData, initialExtras); } public void sendBroadcastAsUser(Intent intent, VUserHandle user) { SpecialComponentList.protectIntent(intent); Context context = VirtualCore.get().getContext(); if (user != null) { intent.putExtra("_VA_|_user_id_", user.getIdentifier()); } context.sendBroadcast(intent); } public boolean bindServiceAsUser(Intent service, ServiceConnection connection, int flags, VUserHandle user) { service = new Intent(service); if (user != null) { service.putExtra("_VA_|_user_id_", user.getIdentifier()); } return VirtualCore.get().getContext().bindService(service, connection, flags); } public void sendBroadcastAsUser(Intent intent, VUserHandle user, String permission) { SpecialComponentList.protectIntent(intent); Context context = VirtualCore.get().getContext(); if (user != null) { intent.putExtra("_VA_|_user_id_", user.getIdentifier()); } // TODO: checkPermission context.sendBroadcast(intent); } boolean handleStaticBroadcast(int appId, ActivityInfo info, Intent intent, PendingResultData result) { Intent realIntent = intent.getParcelableExtra("_VA_|_intent_"); ComponentName component = intent.getParcelableExtra("_VA_|_component_"); int userId = intent.getIntExtra("_VA_|_user_id_", VUserHandle.USER_NULL); if (realIntent == null) { return false; } if (userId < 0) { VLog.w(TAG, "Sent a broadcast without userId " + realIntent); return false; } int vuid = VUserHandle.getUid(userId, appId); return handleUserBroadcast(vuid, info, component, realIntent, result); } private boolean handleUserBroadcast(int vuid, ActivityInfo info, ComponentName component, Intent realIntent, PendingResultData result) { if (component != null && !ComponentUtils.toComponentName(info).equals(component)) { // Verify the component. return false; } String originAction = SpecialComponentList.unprotectAction(realIntent.getAction()); if (originAction != null) { // restore to origin action. realIntent.setAction(originAction); } handleStaticBroadcastAsUser(vuid, info, realIntent, result); return true; } private void handleStaticBroadcastAsUser(int vuid, ActivityInfo info, Intent intent, PendingResultData result) { synchronized (this) { ProcessRecord r = findProcessLocked(info.processName, vuid); if (BROADCAST_NOT_STARTED_PKG && r == null) { r = startProcessIfNeedLocked(info.processName, getUserId(vuid), info.packageName); } if (r != null && r.appThread != null) { performScheduleReceiver(r.client, vuid, info, intent, result); } } } private void performScheduleReceiver(IVClient client, int vuid, ActivityInfo info, Intent intent, PendingResultData result) { ComponentName componentName = ComponentUtils.toComponentName(info); BroadcastSystem.get().broadcastSent(vuid, info, result); try { client.scheduleReceiver(info.processName, componentName, intent, result); } catch (Throwable e) { if (result != null) { result.finish(); } } } @Override public void broadcastFinish(PendingResultData res) { BroadcastSystem.get().broadcastFinish(res); } }