android.app.IActivityManager

Here are the examples of the java api android.app.IActivityManager taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.

36 Examples 7

19 Source : ActivityManagerCompat.java
with GNU General Public License v3.0
from MuntashirAkon

public static int sendBroadcast(Intent intent, @UserIdInt int userHandle) throws RemoteException {
    IActivityManager am = getActivityManager();
    int res;
    IIntentReceiver receiver = new IntentReceiver();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        res = am.broadcastIntentWithFeature(null, null, intent, null, receiver, 0, null, null, null, AppOpsManager.OP_NONE, null, true, false, userHandle);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        res = am.broadcastIntent(null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, null, true, false, userHandle);
    } else {
        res = am.broadcastIntent(null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, true, false, userHandle);
    }
    return res;
}

19 Source : OverlayManagerService.java
with Apache License 2.0
from lulululbj

private void updatereplacedets(final int userId, List<String> targetPackageNames) {
    updateOverlayPaths(userId, targetPackageNames);
    final IActivityManager am = ActivityManager.getService();
    try {
        am.scheduleApplicationInfoChanged(targetPackageNames, userId);
    } catch (RemoteException e) {
    // Intentionally left empty.
    }
}

19 Source : GrantedUriPermissions.java
with Apache License 2.0
from lulululbj

private static GrantedUriPermissions grantClip(IActivityManager am, ClipData clip, int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag, GrantedUriPermissions curPerms) {
    final int N = clip.gereplacedemCount();
    for (int i = 0; i < N; i++) {
        curPerms = granreplacedem(am, clip.gereplacedemAt(i), sourceUid, targetPackage, targetUserId, grantFlags, tag, curPerms);
    }
    return curPerms;
}

19 Source : GrantedUriPermissions.java
with Apache License 2.0
from lulululbj

public void revoke(IActivityManager am) {
    for (int i = mUris.size() - 1; i >= 0; i--) {
        try {
            am.revokeUriPermissionFromOwner(mPermissionOwner, mUris.get(i), mGrantFlags, mSourceUserId);
        } catch (RemoteException e) {
        }
    }
    mUris.clear();
}

19 Source : GrantedUriPermissions.java
with Apache License 2.0
from lulululbj

public static GrantedUriPermissions createFromClip(IActivityManager am, ClipData clip, int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag) {
    if (!checkGrantFlags(grantFlags)) {
        return null;
    }
    GrantedUriPermissions perms = null;
    if (clip != null) {
        perms = grantClip(am, clip, sourceUid, targetPackage, targetUserId, grantFlags, tag, perms);
    }
    return perms;
}

19 Source : PluginManager.java
with Apache License 2.0
from didi

protected ActivityManagerProxy createActivityManagerProxy(IActivityManager origin) throws Exception {
    return new ActivityManagerProxy(this, origin);
}

18 Source : ActivityManagerCompat.java
with GNU General Public License v3.0
from MuntashirAkon

@SuppressWarnings("deprecation")
public static int startActivity(Context context, Intent intent, @UserIdInt int userHandle) throws RemoteException {
    IActivityManager am = getActivityManager();
    String callingPackage = LocalServer.isAMServiceAlive() ? SHELL_PACKAGE_NAME : context.getPackageName();
    int result;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        result = am.startActivityAsUserWithFeature(null, callingPackage, null, intent, intent.getType(), null, null, 0, 0, null, null, userHandle);
    } else {
        result = am.startActivityAsUser(null, callingPackage, intent, intent.getType(), null, null, 0, 0, null, null, userHandle);
    }
    return result;
}

18 Source : ActivityManagerCompat.java
with GNU General Public License v3.0
from MuntashirAkon

@SuppressWarnings("deprecation")
public static ComponentName startService(Context context, Intent intent, @UserIdInt int userHandle, boolean asForeground) throws RemoteException {
    IActivityManager am = getActivityManager();
    String callingPackage = LocalServer.isAMServiceAlive() ? SHELL_PACKAGE_NAME : context.getPackageName();
    ComponentName cn;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        cn = am.startService(null, intent, intent.getType(), asForeground, callingPackage, null, userHandle);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        cn = am.startService(null, intent, intent.getType(), asForeground, callingPackage, userHandle);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        cn = am.startService(null, intent, intent.getType(), callingPackage, userHandle);
    } else
        cn = am.startService(null, intent, intent.getType(), userHandle);
    return cn;
}

18 Source : GrantedUriPermissions.java
with Apache License 2.0
from lulululbj

private static GrantedUriPermissions granreplacedem(IActivityManager am, ClipData.Item item, int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag, GrantedUriPermissions curPerms) {
    if (item.getUri() != null) {
        curPerms = grantUri(am, item.getUri(), sourceUid, targetPackage, targetUserId, grantFlags, tag, curPerms);
    }
    Intent intent = item.getIntent();
    if (intent != null && intent.getData() != null) {
        curPerms = grantUri(am, intent.getData(), sourceUid, targetPackage, targetUserId, grantFlags, tag, curPerms);
    }
    return curPerms;
}

18 Source : GrantedUriPermissions.java
with Apache License 2.0
from lulululbj

private static GrantedUriPermissions grantUri(IActivityManager am, Uri uri, int sourceUid, String targetPackage, int targetUserId, int grantFlags, String tag, GrantedUriPermissions curPerms) {
    try {
        int sourceUserId = ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid));
        uri = ContentProvider.getUriWithoutUserId(uri);
        if (curPerms == null) {
            curPerms = new GrantedUriPermissions(am, grantFlags, sourceUid, tag);
        }
        am.grantUriPermissionFromOwner(curPerms.mPermissionOwner, sourceUid, targetPackage, uri, grantFlags, sourceUserId, targetUserId);
        curPerms.mUris.add(uri);
    } catch (RemoteException e) {
        Slog.e("JobScheduler", "AM dead");
    }
    return curPerms;
}

18 Source : Injector.java
with GNU General Public License v3.0
from Kr328

@SuppressWarnings({ "unused", "RedundantSuppression" })
public clreplaced Injector extends ServiceProxy {

    public static final String TAG = "IFWEnhance";

    private IActivityManager activityManager = null;

    public static void inject(String argument) {
        Log.i(TAG, String.format("Uid = %d Pid = %d", Process.myUid(), Process.myPid()));
        Injector injector = new Injector();
        try {
            injector.install();
            Log.i(TAG, "Inject successfully");
        } catch (Exception e) {
            Log.e(TAG, "Inject failure", e);
        }
    }

    @Override
    protected IBinder onAddService(String name, IBinder service) {
        if (!name.equals("activity"))
            return service;
        try {
            activityManager = (IActivityManager) ObjectResolver.resolve(service, "com.android.server.am.ActivityManagerService", 30);
        } catch (Exception e) {
            Log.e(TAG, "Query original AMS failure", e);
        }
        return service;
    }

    @Override
    protected IBinder onGetService(String name, IBinder service) {
        for (StackTraceElement stack : Thread.currentThread().getStackTrace()) {
            if ("getCommonServicesLocked".equals(stack.getMethodName())) {
                if ("package".equals(name) && activityManager != null) {
                    Log.i(TAG, "Package Manager found");
                    try {
                        IntentFirewall firewall = IntentFirewall.fromActivityManager(activityManager);
                        Binder proxy = ProxyFactory.instance(service, new PackageProxy(IPackageManager.Stub.asInterface(service), firewall));
                        Log.i(TAG, "Package Manager replaced");
                        return proxy;
                    } catch (Exception e) {
                        Log.e(TAG, "Proxy Package Manager failure", e);
                    }
                }
                return service;
            }
        }
        return service;
    }
}

18 Source : ActivityManagerProxy.java
with Apache License 2.0
from didi

/**
 * @author johnsonlee
 */
public clreplaced ActivityManagerProxy implements InvocationHandler {

    private static final String TAG = Constants.TAG_PREFIX + "IActivityManagerProxy";

    public static final int INTENT_SENDER_BROADCAST = 1;

    public static final int INTENT_SENDER_ACTIVITY = 2;

    public static final int INTENT_SENDER_ACTIVITY_RESULT = 3;

    public static final int INTENT_SENDER_SERVICE = 4;

    private PluginManager mPluginManager;

    private IActivityManager mActivityManager;

    public ActivityManagerProxy(PluginManager pluginManager, IActivityManager activityManager) {
        this.mPluginManager = pluginManager;
        this.mActivityManager = activityManager;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("startService".equals(method.getName())) {
            try {
                return startService(proxy, method, args);
            } catch (Throwable e) {
                Log.e(TAG, "Start service error", e);
            }
        } else if ("stopService".equals(method.getName())) {
            try {
                return stopService(proxy, method, args);
            } catch (Throwable e) {
                Log.e(TAG, "Stop Service error", e);
            }
        } else if ("stopServiceToken".equals(method.getName())) {
            try {
                return stopServiceToken(proxy, method, args);
            } catch (Throwable e) {
                Log.e(TAG, "Stop service token error", e);
            }
        } else if ("bindService".equals(method.getName())) {
            try {
                return bindService(proxy, method, args);
            } catch (Throwable e) {
                Log.w(TAG, e);
            }
        } else if ("unbindService".equals(method.getName())) {
            try {
                return unbindService(proxy, method, args);
            } catch (Throwable e) {
                Log.w(TAG, e);
            }
        } else if ("getIntentSender".equals(method.getName())) {
            try {
                getIntentSender(method, args);
            } catch (Exception e) {
                Log.w(TAG, e);
            }
        } else if ("overridePendingTransition".equals(method.getName())) {
            try {
                overridePendingTransition(method, args);
            } catch (Exception e) {
                Log.w(TAG, e);
            }
        }
        try {
            // sometimes system binder has problems.
            return method.invoke(this.mActivityManager, args);
        } catch (Throwable th) {
            Throwable c = th.getCause();
            if (c != null && c instanceof DeadObjectException) {
                // retry connect to system binder
                IBinder ams = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                if (ams != null) {
                    IActivityManager am = ActivityManagerNative.asInterface(ams);
                    mActivityManager = am;
                }
            }
            Throwable cause = th;
            do {
                if (cause instanceof RemoteException) {
                    throw cause;
                }
            } while ((cause = cause.getCause()) != null);
            throw c != null ? c : th;
        }
    }

    protected Object startService(Object proxy, Method method, Object[] args) throws Throwable {
        IApplicationThread appThread = (IApplicationThread) args[0];
        Intent target = (Intent) args[1];
        ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);
        if (null == resolveInfo || null == resolveInfo.serviceInfo) {
            // is host service
            return method.invoke(this.mActivityManager, args);
        }
        return startDelegateServiceForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_START_SERVICE);
    }

    protected Object stopService(Object proxy, Method method, Object[] args) throws Throwable {
        Intent target = (Intent) args[1];
        ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);
        if (null == resolveInfo || null == resolveInfo.serviceInfo) {
            // is hot service
            return method.invoke(this.mActivityManager, args);
        }
        startDelegateServiceForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_STOP_SERVICE);
        return 1;
    }

    protected Object stopServiceToken(Object proxy, Method method, Object[] args) throws Throwable {
        ComponentName component = (ComponentName) args[0];
        Intent target = new Intent().setComponent(component);
        ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);
        if (null == resolveInfo || null == resolveInfo.serviceInfo) {
            // is hot service
            return method.invoke(this.mActivityManager, args);
        }
        startDelegateServiceForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_STOP_SERVICE);
        return true;
    }

    protected Object bindService(Object proxy, Method method, Object[] args) throws Throwable {
        Intent target = (Intent) args[2];
        ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);
        if (null == resolveInfo || null == resolveInfo.serviceInfo) {
            // is host service
            return method.invoke(this.mActivityManager, args);
        }
        Bundle bundle = new Bundle();
        PluginUtil.putBinder(bundle, "sc", (IBinder) args[4]);
        startDelegateServiceForTarget(target, resolveInfo.serviceInfo, bundle, RemoteService.EXTRA_COMMAND_BIND_SERVICE);
        mPluginManager.getComponentsHandler().remberIServiceConnection((IBinder) args[4], target);
        return 1;
    }

    protected Object unbindService(Object proxy, Method method, Object[] args) throws Throwable {
        IBinder iServiceConnection = (IBinder) args[0];
        Intent target = mPluginManager.getComponentsHandler().forgetIServiceConnection(iServiceConnection);
        if (target == null) {
            // is host service
            return method.invoke(this.mActivityManager, args);
        }
        ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);
        startDelegateServiceForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_UNBIND_SERVICE);
        return true;
    }

    protected ComponentName startDelegateServiceForTarget(Intent target, ServiceInfo serviceInfo, Bundle extras, int command) {
        Intent wrapperIntent = wrapperTargetIntent(target, serviceInfo, extras, command);
        return mPluginManager.getHostContext().startService(wrapperIntent);
    }

    protected Intent wrapperTargetIntent(Intent target, ServiceInfo serviceInfo, Bundle extras, int command) {
        // fill in service with ComponentName
        target.setComponent(new ComponentName(serviceInfo.packageName, serviceInfo.name));
        String pluginLocation = mPluginManager.getLoadedPlugin(target.getComponent()).getLocation();
        // start delegate service to run plugin service inside
        boolean local = PluginUtil.isLocalService(serviceInfo);
        Clreplaced<? extends Service> delegate = local ? LocalService.clreplaced : RemoteService.clreplaced;
        Intent intent = new Intent();
        intent.setClreplaced(mPluginManager.getHostContext(), delegate);
        intent.putExtra(RemoteService.EXTRA_TARGET, target);
        intent.putExtra(RemoteService.EXTRA_COMMAND, command);
        intent.putExtra(RemoteService.EXTRA_PLUGIN_LOCATION, pluginLocation);
        if (extras != null) {
            intent.putExtras(extras);
        }
        return intent;
    }

    protected void getIntentSender(Method method, Object[] args) {
        String hostPackageName = mPluginManager.getHostContext().getPackageName();
        args[1] = hostPackageName;
        Intent target = ((Intent[]) args[5])[0];
        int intentSenderType = (int) args[0];
        if (intentSenderType == INTENT_SENDER_ACTIVITY) {
            mPluginManager.getComponentsHandler().transformIntentToExplicitAsNeeded(target);
            mPluginManager.getComponentsHandler().markIntentIfNeeded(target);
        } else if (intentSenderType == INTENT_SENDER_SERVICE) {
            ResolveInfo resolveInfo = this.mPluginManager.resolveService(target, 0);
            if (resolveInfo != null && resolveInfo.serviceInfo != null) {
                // find plugin service
                Intent wrapperIntent = wrapperTargetIntent(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_START_SERVICE);
                ((Intent[]) args[5])[0] = wrapperIntent;
            }
        } else if (intentSenderType == INTENT_SENDER_BROADCAST) {
        // no action
        }
    }

    protected void overridePendingTransition(Method method, Object[] args) {
        String hostPackageName = mPluginManager.getHostContext().getPackageName();
        args[1] = hostPackageName;
    }
}

18 Source : ActivityManagerNativeWorker.java
with Apache License 2.0
from baidu

/**
 * ActivityManagerNativeWorker
 *
 * @author liuhaitao
 * @since 2018-01-04
 */
public clreplaced ActivityManagerNativeWorker extends InterfaceProxy {

    /**
     * 构造方法
     */
    public ActivityManagerNativeWorker() {
        super(Constants.ACTIVE_MANAGER_NATIVE_CLreplaced);
    }

    /**
     * DEBUG 开关
     */
    public static final boolean DEBUG = false & Constants.DEBUG;

    /**
     * TAG
     */
    private static final String TAG = "ActivityManagerNativeWorker";

    /**
     * 系统真正的IActivityManager aidl接口
     */
    public IActivityManager mTarget;

    /**
     * 宿主包名
     */
    private Context mHostContext = null;

    /**
     * INVALID_USER_ID
     */
    private static final int INVALID_USER_ID = -11111;

    /**
     * 设置宿主包名
     *
     * @param hostContext hostContext
     */
    public void setHostContext(Context hostContext) {
        mHostContext = hostContext;
    }

    public IIntentSender getIntentSender(int type, String packageName, IBinder token, String resultWho, int requestCode, Intent[] intents, String[] resolvedTypes, int flags, Bundle options, int userId) throws RemoteException {
        remapIntents(mHostContext, intents, false);
        return mTarget.getIntentSender(type, mHostContext.getPackageName(), token, resultWho, requestCode, intents, resolvedTypes, flags, options, userId);
    }

    public IIntentSender getIntentSender(int type, String packageName, IBinder token, String resultWho, int requestCode, Intent[] intents, String[] resolvedTypes, int flags) throws RemoteException {
        remapIntents(mHostContext, intents, false);
        return mTarget.getIntentSender(type, mHostContext.getPackageName(), token, resultWho, requestCode, intents, resolvedTypes, flags);
    }

    public IIntentSender getIntentSender(int type, String packageName, IBinder token, String reesultWho, int requestCode, Intent[] intents, String[] resolvedTypes, int flags, Bundle bundle) throws RemoteException {
        remapIntents(mHostContext, intents, false);
        return mTarget.getIntentSender(type, mHostContext.getPackageName(), token, reesultWho, requestCode, intents, resolvedTypes, flags, bundle);
    }

    public IIntentSender getIntentSender(int type, String packageName, IBinder token, String resultWho, int requestCode, Intent intent, String resolvedType, int flags) {
        Intent[] intents = { intent };
        remapIntents(mHostContext, intents, false);
        return mTarget.getIntentSender(type, mHostContext.getPackageName(), token, resultWho, requestCode, intent, resolvedType, flags);
    }

    public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
        List<ActivityManager.RunningAppProcessInfo> apps = mTarget.getRunningAppProcesses();
        // TODO 临时加上捕获打出日志,这里有发现过crash
        try {
            String pluginPkg = Util.getCallingPulingPackage();
            if (pluginPkg != null) {
                int pid = android.os.Process.myPid();
                for (ActivityManager.RunningAppProcessInfo app : apps) {
                    if (app.pid == pid) {
                        // 在包名列表里加上插件的包名,小米的ROM在显示Toast之前,会获取RunningProcesses,遍历进程的pkgList,如果没有匹配到,
                        // 认为invisible to user,就不显示了。导致Toast不可用。
                        String[] pkgList = null;
                        String[] originalList = app.pkgList;
                        if (originalList != null) {
                            pkgList = new String[originalList.length + 1];
                            System.arraycopy(app.pkgList, 0, pkgList, 0, originalList.length);
                            pkgList[originalList.length] = pluginPkg;
                        }
                        app.processName = pluginPkg;
                        app.pkgList = pkgList;
                        break;
                    }
                }
            }
        } catch (Exception e) {
            if (DEBUG) {
                e.printStackTrace();
            }
        }
        return apps;
    }

    public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String requiredPermission) {
        return mTarget.registerReceiver(caller, mHostContext.getPackageName(), receiver, filter, requiredPermission);
    }

    public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String requiredPermission, int user) {
        return mTarget.registerReceiver(caller, mHostContext.getPackageName(), receiver, filter, requiredPermission, user);
    }

    /**
     * Android O 方法兼容适配。
     */
    public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String requiredPermission, int userId, int flags) {
        return mTarget.registerReceiver(caller, mHostContext.getPackageName(), receiver, filter, requiredPermission, userId, flags);
    }

    /*
    public List getTasks(int maxNum, int flags, IThumbnailReceiver receiver) throws RemoteException {
        com.baidu.android.gporter.gpt.Util.printClreplacedStack();
        List list = target.getTasks(maxNum, flags, receiver);

        ProxyEnvironment instance = ProxyEnvironment.getInstance(mCurrentPackageName);
        if (instance != null) {
            List<Activity> stacks = instance.getActivityStack();
            if (stacks != null && stacks.size() > 0) {
                ActivityGroup activityGroup = (ActivityGroup) stacks.get(0);
                if (activityGroup.getCurrentActivity() == null) {
                    return list;
                }
                for (Object value : list) {
                    if (value instanceof RunningTaskInfo) {
                        RunningTaskInfo info = (RunningTaskInfo) value;
                        if (info.topActivity != null) {
                            if (info.topActivity.getClreplacedName().equalsIgnoreCase(ActivityProxy.clreplaced.getName())) {
                                info.topActivity = activityGroup.getCurrentActivity().getComponentName();
                            }
                        }
                    }
                }
            }

        }

        return list;
    }
*/
    /**
     * remapIntents
     *
     * @param hostContext Context
     * @param intents     Intent[]
     * @param dealMode    true or false
     */
    private static void remapIntents(Context hostContext, Intent[] intents, boolean dealMode) {
        if (intents == null) {
            return;
        }
        if (DEBUG) {
            Log.d(TAG, "--- remapIntents !");
        }
        for (int i = 0; i < intents.length; i++) {
            RemapingUtil.remapActivityIntent(hostContext, intents[i], dealMode);
            RemapingUtil.remapReceiverIntent(hostContext, intents[i]);
            RemapingUtil.remapServiceIntent(hostContext, intents[i]);
        }
    }

    public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType) {
        RemapingUtil.remapServiceIntent(mHostContext, service);
        return mTarget.startService(caller, service, resolvedType);
    }

    public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, int userId) {
        RemapingUtil.remapServiceIntent(mHostContext, service);
        return mTarget.startService(caller, service, resolvedType, userId);
    }

    public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, String callingPackage, int userId) {
        RemapingUtil.remapServiceIntent(mHostContext, service);
        return mTarget.startService(caller, service, resolvedType, callingPackage, userId);
    }

    public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, String callingPackage, int userId, IBinder token, int l) {
        RemapingUtil.remapServiceIntent(mHostContext, service);
        return mTarget.startService(caller, service, resolvedType, callingPackage, userId, token, l);
    }

    public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, int i, Notification notification, String callingPackage, int userId) {
        RemapingUtil.remapServiceIntent(mHostContext, service);
        return mTarget.startService(caller, service, resolvedType, i, notification, callingPackage, userId);
    }

    public int stopService(IApplicationThread caller, Intent service, String resolvedType) {
        if (service.getComponent() != null && ProxyEnvironment.hasInstance(service.getComponent().getPackageName())) {
            return ServiceProxy.stopServiceExternal(service.getComponent());
        } else {
            return mTarget.stopService(caller, service, resolvedType);
        }
    }

    public int stopService(IApplicationThread caller, Intent service, String resolvedType, int userId) {
        if (service.getComponent() != null && ProxyEnvironment.hasInstance(service.getComponent().getPackageName())) {
            return ServiceProxy.stopServiceExternal(service.getComponent());
        } else {
            return mTarget.stopService(caller, service, resolvedType, userId);
        }
    }

    public int bindService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags) {
        return bindService(caller, token, service, resolvedType, connection, flags, INVALID_USER_ID);
    }

    public int bindService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) {
        token = getActivityToken(token);
        RemapingUtil.remapServiceIntent(mHostContext, service);
        if (userId == INVALID_USER_ID) {
            return mTarget.bindService(caller, token, service, resolvedType, connection, flags);
        } else {
            return mTarget.bindService(caller, token, service, resolvedType, connection, flags, userId);
        }
    }

    /**
     * android 6.0
     */
    public int bindService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, String callingPackage, int userId) {
        RemapingUtil.remapServiceIntent(mHostContext, service);
        return mTarget.bindService(caller, token, service, resolvedType, connection, flags, callingPackage, userId);
    }

    public boolean unbindService(IServiceConnection connection) {
        return mTarget.unbindService(connection);
    }

    /**
     * android 2.x
     */
    public int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String requiredPermission, boolean serialized, boolean sticky) {
        remapBroadcastIntent(intent);
        return mTarget.broadcastIntent(caller, intent, resolvedType, resultTo, resultCode, resultData, map, requiredPermission, serialized, sticky);
    }

    /**
     * android 4.x
     */
    public int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String requiredPermission, boolean serialized, boolean sticky, int userId) {
        remapBroadcastIntent(intent);
        return mTarget.broadcastIntent(caller, intent, resolvedType, resultTo, resultCode, resultData, map, requiredPermission, serialized, sticky, userId);
    }

    /**
     * android 5.x
     */
    public int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId) {
        remapBroadcastIntent(intent);
        return mTarget.broadcastIntent(caller, intent, resolvedType, resultTo, resultCode, resultData, map, requiredPermission, appOp, serialized, sticky, userId);
    }

    /**
     * android 6.x
     */
    public int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String[] requiredPermissions, int appOp, Bundle options, boolean serialized, boolean sticky, int userId) {
        remapBroadcastIntent(intent);
        return mTarget.broadcastIntent(caller, intent, resolvedType, resultTo, resultCode, resultData, map, requiredPermissions, appOp, options, serialized, sticky, userId);
    }

    /**
     * 处理 创建和删除 桌面快捷方式 intent
     *
     * @param intent Intent
     * @return true or false
     */
    private boolean remapShortcutIntent(Intent intent) {
        boolean result = false;
        if (Constants.ACTION_INSTALL_SHORT_CUT.equals(intent.getAction()) || Constants.ACTION_UNINSTALL_SHORT_CUT.equals(intent.getAction())) {
            // 根据shortcut启动的component做判断。
            Intent shortcutIntent = intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
            ComponentName cn = shortcutIntent.getComponent();
            String packageName = cn.getPackageName();
            if (GPTInstrumentation.isPlugin(packageName) && ProxyEnvironment.hasInstance(packageName)) {
                ProxyEnvironment.getInstance(packageName).remapShortCutCreatorIntent(intent);
                result = true;
            }
        }
        return result;
    }

    /**
     * remapBroadcastIntent
     * <p>
     * 函数思路
     * 静态转动态应该还需要保留
     * 插件之间调用需要 remap 代理
     * Registter 不需要remap
     * Send的时候只需要把静态的remap
     *
     * @param intent Intent
     */
    private void remapBroadcastIntent(Intent intent) {
        boolean result = remapShortcutIntent(intent);
        if (result) {
            // 如果是 shortcut 的intent,直接返回不需要处理。
            return;
        }
        // 这里只remap插件manifest中声明的静态receiver。
        RemapingUtil.remapReceiverIntent(mHostContext, intent);
    }

    /**
     * 2.3
     */
    public ContentProviderHolder getContentProvider(IApplicationThread caller, String name) {
        ContentProviderHolder holder = getContentProviderHolder(mHostContext, name);
        if (holder != null) {
            return holder;
        }
        return mTarget.getContentProvider(caller, name);
    }

    /**
     * 4.x
     */
    public ContentProviderHolder getContentProvider(IApplicationThread caller, String name, boolean stable) {
        ContentProviderHolder holder = getContentProviderHolder(mHostContext, name);
        if (holder != null) {
            return holder;
        }
        return mTarget.getContentProvider(caller, name, stable);
    }

    /**
     * 5.x 6.0
     */
    public ContentProviderHolder getContentProvider(IApplicationThread caller, String name, int userId, boolean stable) {
        ContentProviderHolder holder = getContentProviderHolder(mHostContext, name);
        if (holder != null) {
            return holder;
        }
        return mTarget.getContentProvider(caller, name, userId, stable);
    }

    /**
     * getContentProviderHolder
     *
     * @param hostContext Context
     * @param authority   authority
     * @return ContentProviderHolder
     */
    public static ContentProviderHolder getContentProviderHolder(Context hostContext, String authority) {
        ContentProviderHolder holder = null;
        String packageName = ContentProviderProxy.getProviderPackageName(hostContext, authority);
        if (packageName == null || packageName.length() == 0) {
            return null;
        }
        GPTPackageInfo pkginfo = GPTPackageManager.getInstance(hostContext).getPackageInfo(packageName);
        if (pkginfo == null) {
            return null;
        }
        // 插件是否运行在主进程
        boolean runOnHostProcess = pkginfo.isUnionProcess;
        // 中转代理provider
        String proxyAuthority = hostContext.getPackageName() + "_" + ContentProviderProxy.AUTHORITY;
        if (!runOnHostProcess) {
            proxyAuthority = hostContext.getPackageName() + "_" + ContentProviderProxy.AUTHORITY_EXT;
        }
        Uri uri = Uri.parse("content://" + proxyAuthority);
        Cursor c = null;
        String[] projection = { packageName, authority };
        c = hostContext.getContentResolver().query(uri, projection, null, null, null);
        if (c != null) {
            Bundle bundle = c.getExtras();
            holder = bundle.getParcelable("provider");
            c.close();
        }
        return holder;
    }

    public int startActivity(IApplicationThread caller, Intent intent, String resolvedType, Uri[] grantedUriPermissions, int grantedMode, IBinder resultTo, String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug) {
        RemapingUtil.remapActivityIntent(mHostContext, intent);
        return mTarget.startActivity(caller, intent, resolvedType, grantedUriPermissions, grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded, debug);
    }

    public int startActivity(IApplicationThread caller, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags, String profileFile, ParcelFileDescriptor profileFd, Bundle options) {
        RemapingUtil.remapActivityIntent(mHostContext, intent);
        return mTarget.startActivity(caller, intent, resolvedType, resultTo, resultWho, requestCode, flags, profileFile, profileFd, options);
    }

    public int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags, String profileFile, ParcelFileDescriptor profileFd, Bundle options) {
        try {
            RemapingUtil.remapActivityIntent(mHostContext, intent);
        } catch (Exception e) {
            if (DEBUG) {
                e.printStackTrace();
            }
        }
        return mTarget.startActivity(caller, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, flags, profileFile, profileFd, options);
    }

    public int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags, ProfilerInfo profilerInfo, Bundle options) {
        RemapingUtil.remapActivityIntent(mHostContext, intent);
        return mTarget.startActivity(caller, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, flags, profilerInfo, options);
    }

    public int startActivity(IApplicationThread caller, Intent intent, String resolvedType, Uri[] grantedUriPermissions, int grantedMode, IBinder resultTo, String resultWho, int requestCode, boolean onlyIfNeeded, boolean debug, String profileFile, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
        RemapingUtil.remapActivityIntent(mHostContext, intent);
        return mTarget.startActivity(caller, intent, resolvedType, grantedUriPermissions, grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler);
    }

    public void unstableProviderDied(IBinder connection) {
        if (connection == null) {
            // 我们自己的provider代理,此connection为null,如果传递给系统的ActivityManagerService会报空指针。
            return;
        }
        mTarget.unstableProviderDied(connection);
    }

    public int getTaskForActivity(IBinder token, boolean onlyRoot) {
        return mTarget.getTaskForActivity(getActivityToken(token), onlyRoot);
    }

    public boolean isTopOfTask(IBinder token) {
        return mTarget.isTopOfTask(getActivityToken(token));
    }

    /**
     * getActivityToken
     *
     * @param token IBinder
     * @return IBinder
     */
    private IBinder getActivityToken(IBinder token) {
        if (token != null) {
            // ContextImpl.getActivityToken
            // 是activity的话
            String clreplacedName = "android.app.LocalActivityManager$LocalActivityRecord";
            Clreplaced clazz = null;
            try {
                clazz = Clreplaced.forName(clreplacedName);
            } catch (ClreplacedNotFoundException e) {
                if (DEBUG) {
                    e.printStackTrace();
                }
            }
            if (clazz != null && token.getClreplaced().equals(clazz)) {
                Activity activity = (Activity) JavaCalls.getField(token, "activity");
                if (activity != null) {
                    // token转为parent activity
                    token = (IBinder) JavaCalls.getField(activity.getParent(), "mToken");
                }
            }
        }
        return token;
    }
}

17 Source : SettingsHelper.java
with Apache License 2.0
from RealMoMo

/**
 * Sets the locale specified. Input data is the byte representation of a
 * BCP-47 language tag. For backwards compatibility, strings of the form
 * {@code ll_CC} are also accepted, where {@code ll} is a two letter language
 * code and {@code CC} is a two letter country code.
 *
 * @param data the locale string in bytes.
 */
void setLocaleData(byte[] data, int size) {
    // Check if locale was set by the user:
    Configuration conf = mContext.getResources().getConfiguration();
    // TODO: The following is not working as intended because the network is forcing a locale
    // change after registering. Need to find some other way to detect if the user manually
    // changed the locale
    // Don't change if user set it in the SetupWizard
    if (conf.userSetLocale)
        return;
    final String[] availableLocales = mContext.getreplacedets().getLocales();
    // Replace "_" with "-" to deal with older backups.
    String localeCode = new String(data, 0, size).replace('_', '-');
    Locale loc = null;
    for (int i = 0; i < availableLocales.length; i++) {
        if (availableLocales[i].equals(localeCode)) {
            loc = Locale.forLanguageTag(localeCode);
            break;
        }
    }
    // Couldn't find the saved locale in this version of the software
    if (loc == null)
        return;
    try {
        IActivityManager am = ActivityManagerNative.getDefault();
        Configuration config = am.getConfiguration();
        config.locale = loc;
        // indicate this isn't some preplaceding default - the user wants this remembered
        config.userSetLocale = true;
        am.updateConfiguration(config);
    } catch (RemoteException e) {
    // Intentionally left blank
    }
}

17 Source : SettingsHelper.java
with Apache License 2.0
from RealMoMo

/**
 * Sets the locale specified. Input data is the byte representation of a
 * BCP-47 language tag. For backwards compatibility, strings of the form
 * {@code ll_CC} are also accepted, where {@code ll} is a two letter language
 * code and {@code CC} is a two letter country code.
 *
 * @param data the locale string in bytes.
 */
void setLocaleData(byte[] data, int size) {
    // Check if locale was set by the user:
    Configuration conf = mContext.getResources().getConfiguration();
    // TODO: The following is not working as intended because the network is forcing a locale
    // change after registering. Need to find some other way to detect if the user manually
    // changed the locale
    // Don't change if user set it in the SetupWizard
    if (conf.userSetLocale)
        return;
    final String[] availableLocales = mContext.getreplacedets().getLocales();
    // Replace "_" with "-" to deal with older backups.
    String localeCode = new String(data, 0, size).replace('_', '-');
    Locale loc = null;
    for (int i = 0; i < availableLocales.length; i++) {
        if (availableLocales[i].equals(localeCode)) {
            loc = Locale.forLanguageTag(localeCode);
            break;
        }
    }
    // Couldn't find the saved locale in this version of the software
    if (loc == null)
        return;
    try {
        IActivityManager am = ActivityManager.getService();
        Configuration config = am.getConfiguration();
        config.locale = loc;
        // indicate this isn't some preplaceding default - the user wants this remembered
        config.userSetLocale = true;
        am.updateConfiguration(config);
    } catch (RemoteException e) {
    // Intentionally left blank
    }
}

17 Source : ActivityManagerCompat.java
with GNU General Public License v3.0
from MuntashirAkon

@Nullable
public static IContentProvider getContentProviderExternal(String name, int userId, IBinder token, String tag) throws RemoteException {
    IActivityManager am = getActivityManager();
    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            return am.getContentProviderExternal(name, userId, token, tag).provider;
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            return ((android.app.ContentProviderHolder) am.getContentProviderExternal(name, userId, token)).provider;
        } else {
            return ((IActivityManager.ContentProviderHolder) am.getContentProviderExternal(name, userId, token)).provider;
        }
    } catch (NullPointerException e) {
        return null;
    }
}

17 Source : GrantedUriPermissions.java
with Apache License 2.0
from lulululbj

public static GrantedUriPermissions createFromIntent(IActivityManager am, Intent intent, int sourceUid, String targetPackage, int targetUserId, String tag) {
    int grantFlags = intent.getFlags();
    if (!checkGrantFlags(grantFlags)) {
        return null;
    }
    GrantedUriPermissions perms = null;
    Uri data = intent.getData();
    if (data != null) {
        perms = grantUri(am, data, sourceUid, targetPackage, targetUserId, grantFlags, tag, perms);
    }
    ClipData clip = intent.getClipData();
    if (clip != null) {
        perms = grantClip(am, clip, sourceUid, targetPackage, targetUserId, grantFlags, tag, perms);
    }
    return perms;
}

17 Source : BroadcastReceiver.java
with Apache License 2.0
from lulululbj

/**
 * Provide a binder to an already-bound service.  This method is synchronous
 * and will not start the target service if it is not present, so it is safe
 * to call from {@link #onReceive}.
 *
 * For peekService() to return a non null {@link android.os.IBinder} interface
 * the service must have published it before. In other words some component
 * must have called {@link android.content.Context#bindService(Intent, ServiceConnection, int)} on it.
 *
 * @param myContext The Context that had been preplaceded to {@link #onReceive(Context, Intent)}
 * @param service Identifies the already-bound service you wish to use. See
 * {@link android.content.Context#bindService(Intent, ServiceConnection, int)}
 * for more information.
 */
public IBinder peekService(Context myContext, Intent service) {
    IActivityManager am = ActivityManager.getService();
    IBinder binder = null;
    try {
        service.prepareToLeaveProcess(myContext);
        binder = am.peekService(service, service.resolveTypeIfNeeded(myContext.getContentResolver()), myContext.getOpPackageName());
    } catch (RemoteException e) {
    }
    return binder;
}

17 Source : ActivityManagerProxy.java
with Apache License 2.0
from didi

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if ("startService".equals(method.getName())) {
        try {
            return startService(proxy, method, args);
        } catch (Throwable e) {
            Log.e(TAG, "Start service error", e);
        }
    } else if ("stopService".equals(method.getName())) {
        try {
            return stopService(proxy, method, args);
        } catch (Throwable e) {
            Log.e(TAG, "Stop Service error", e);
        }
    } else if ("stopServiceToken".equals(method.getName())) {
        try {
            return stopServiceToken(proxy, method, args);
        } catch (Throwable e) {
            Log.e(TAG, "Stop service token error", e);
        }
    } else if ("bindService".equals(method.getName())) {
        try {
            return bindService(proxy, method, args);
        } catch (Throwable e) {
            Log.w(TAG, e);
        }
    } else if ("unbindService".equals(method.getName())) {
        try {
            return unbindService(proxy, method, args);
        } catch (Throwable e) {
            Log.w(TAG, e);
        }
    } else if ("getIntentSender".equals(method.getName())) {
        try {
            getIntentSender(method, args);
        } catch (Exception e) {
            Log.w(TAG, e);
        }
    } else if ("overridePendingTransition".equals(method.getName())) {
        try {
            overridePendingTransition(method, args);
        } catch (Exception e) {
            Log.w(TAG, e);
        }
    }
    try {
        // sometimes system binder has problems.
        return method.invoke(this.mActivityManager, args);
    } catch (Throwable th) {
        Throwable c = th.getCause();
        if (c != null && c instanceof DeadObjectException) {
            // retry connect to system binder
            IBinder ams = ServiceManager.getService(Context.ACTIVITY_SERVICE);
            if (ams != null) {
                IActivityManager am = ActivityManagerNative.asInterface(ams);
                mActivityManager = am;
            }
        }
        Throwable cause = th;
        do {
            if (cause instanceof RemoteException) {
                throw cause;
            }
        } while ((cause = cause.getCause()) != null);
        throw c != null ? c : th;
    }
}

17 Source : UiDevice.java
with Mozilla Public License 2.0
from coolwho

public void initialize(ShellUiAutomatorBridge uiAutomatorBridge) {
    mUiAutomationBridge = uiAutomatorBridge;
    // 监听activity变化,用于getAct
    try {
        IActivityManager am = ActivityManagerNative.getDefault();
        am.setActivityController(new DummyActivityController());
    } catch (RemoteException e) {
    }
    UiAutomation uiAutomation = uiAutomatorBridge.getUiAutomation();
    uiAutomation.setOnAccessibilityEventListener(new OnAccessibilityEventListener() {

        public void onAccessibilityEvent(AccessibilityEvent event) {
            synchronized (onAccessibilityEventListeners) {
                for (OnAccessibilityEventListener listener : onAccessibilityEventListeners) {
                    listener.onAccessibilityEvent(event);
                }
            }
        }
    });
}

17 Source : UiAutomationShellWrapper.java
with Mozilla Public License 2.0
from coolwho

public void setRunAsMonkey(boolean isSet) {
    IActivityManager am = ActivityManagerNative.getDefault();
    if (am == null) {
        throw new RuntimeException("Can't manage monkey status; is the system running?");
    }
    try {
        if (isSet) {
            am.setActivityController(new DummyActivityController());
        } else {
            am.setActivityController(null);
        }
    } catch (RemoteException e) {
        throw new RuntimeException(e);
    }
}

17 Source : BroadcastReceiver.java
with MIT License
from BaoBaoJianqiang

/**
 * Provide a binder to an already-running service.  This method is synchronous
 * and will not start the target service if it is not present, so it is safe
 * to call from {@link #onReceive}.
 *
 * @param myContext The Context that had been preplaceded to {@link #onReceive(Context, Intent)}
 * @param service The Intent indicating the service you wish to use.  See {@link
 * Context#startService(Intent)} for more information.
 */
public IBinder peekService(Context myContext, Intent service) {
    IActivityManager am = ActivityManagerNative.getDefault();
    IBinder binder = null;
    try {
        service.prepareToLeaveProcess(myContext);
        binder = am.peekService(service, service.resolveTypeIfNeeded(myContext.getContentResolver()), myContext.getOpPackageName());
    } catch (RemoteException e) {
    }
    return binder;
}

17 Source : BroadcastReceiver.java
with MIT License
from BaoBaoJianqiang

/**
 * Provide a binder to an already-running service.  This method is synchronous
 * and will not start the target service if it is not present, so it is safe
 * to call from {@link #onReceive}.
 *
 * @param myContext The Context that had been preplaceded to {@link #onReceive(Context, Intent)}
 * @param service The Intent indicating the service you wish to use.  See {@link
 * Context#startService(Intent)} for more information.
 */
public IBinder peekService(Context myContext, Intent service) {
    IActivityManager am = ActivityManagerNative.getDefault();
    IBinder binder = null;
    try {
        service.prepareToLeaveProcess();
        binder = am.peekService(service, service.resolveTypeIfNeeded(myContext.getContentResolver()), myContext.getOpPackageName());
    } catch (RemoteException e) {
    }
    return binder;
}

16 Source : TaskPositioningController.java
with Apache License 2.0
from lulululbj

/**
 * Controller for task positioning by drag.
 */
clreplaced TaskPositioningController {

    private final WindowManagerService mService;

    private final InputManagerService mInputManager;

    private final InputMonitor mInputMonitor;

    private final IActivityManager mActivityManager;

    private final Handler mHandler;

    @GuardedBy("WindowManagerSerivce.mWindowMap")
    @Nullable
    private TaskPositioner mTaskPositioner;

    boolean isPositioningLocked() {
        return mTaskPositioner != null;
    }

    InputWindowHandle getDragWindowHandleLocked() {
        return mTaskPositioner != null ? mTaskPositioner.mDragWindowHandle : null;
    }

    TaskPositioningController(WindowManagerService service, InputManagerService inputManager, InputMonitor inputMonitor, IActivityManager activityManager, Looper looper) {
        mService = service;
        mInputMonitor = inputMonitor;
        mInputManager = inputManager;
        mActivityManager = activityManager;
        mHandler = new Handler(looper);
    }

    boolean startMovingTask(IWindow window, float startX, float startY) {
        WindowState win = null;
        synchronized (mService.mWindowMap) {
            win = mService.windowForClientLocked(null, window, false);
            // win shouldn't be null here, preplaced it down to startPositioningLocked
            // to get warning if it's null.
            if (!startPositioningLocked(win, false, /*resize*/
            false, /*preserveOrientation*/
            startX, startY)) {
                return false;
            }
        }
        try {
            mActivityManager.setFocusedTask(win.getTask().mTaskId);
        } catch (RemoteException e) {
        }
        return true;
    }

    void handleTapOutsideTask(DisplayContent displayContent, int x, int y) {
        mHandler.post(() -> {
            int taskId = -1;
            synchronized (mService.mWindowMap) {
                final Task task = displayContent.findTaskForResizePoint(x, y);
                if (task != null) {
                    if (!startPositioningLocked(task.getTopVisibleAppMainWindow(), true, /*resize*/
                    task.preserveOrientationOnResize(), x, y)) {
                        return;
                    }
                    taskId = task.mTaskId;
                } else {
                    taskId = displayContent.taskIdFromPoint(x, y);
                }
            }
            if (taskId >= 0) {
                try {
                    mActivityManager.setFocusedTask(taskId);
                } catch (RemoteException e) {
                }
            }
        });
    }

    private boolean startPositioningLocked(WindowState win, boolean resize, boolean preserveOrientation, float startX, float startY) {
        if (DEBUG_TASK_POSITIONING)
            Slog.d(TAG_WM, "startPositioningLocked: " + "win=" + win + ", resize=" + resize + ", preserveOrientation=" + preserveOrientation + ", {" + startX + ", " + startY + "}");
        if (win == null || win.getAppToken() == null) {
            Slog.w(TAG_WM, "startPositioningLocked: Bad window " + win);
            return false;
        }
        if (win.mInputChannel == null) {
            Slog.wtf(TAG_WM, "startPositioningLocked: " + win + " has no input channel, " + " probably being removed");
            return false;
        }
        final DisplayContent displayContent = win.getDisplayContent();
        if (displayContent == null) {
            Slog.w(TAG_WM, "startPositioningLocked: Invalid display content " + win);
            return false;
        }
        Display display = displayContent.getDisplay();
        mTaskPositioner = TaskPositioner.create(mService);
        mTaskPositioner.register(displayContent);
        mInputMonitor.updateInputWindowsLw(true);
        // We need to grab the touch focus so that the touch events during the
        // resizing/scrolling are not sent to the app. 'win' is the main window
        // of the app, it may not have focus since there might be other windows
        // on top (eg. a dialog window).
        WindowState transferFocusFromWin = win;
        if (mService.mCurrentFocus != null && mService.mCurrentFocus != win && mService.mCurrentFocus.mAppToken == win.mAppToken) {
            transferFocusFromWin = mService.mCurrentFocus;
        }
        if (!mInputManager.transferTouchFocus(transferFocusFromWin.mInputChannel, mTaskPositioner.mServerChannel)) {
            Slog.e(TAG_WM, "startPositioningLocked: Unable to transfer touch focus");
            mTaskPositioner.unregister();
            mTaskPositioner = null;
            mInputMonitor.updateInputWindowsLw(true);
            return false;
        }
        mTaskPositioner.startDrag(win, resize, preserveOrientation, startX, startY);
        return true;
    }

    void finishTaskPositioning() {
        mHandler.post(() -> {
            if (DEBUG_TASK_POSITIONING)
                Slog.d(TAG_WM, "finishPositioning");
            synchronized (mService.mWindowMap) {
                if (mTaskPositioner != null) {
                    mTaskPositioner.unregister();
                    mTaskPositioner = null;
                    mInputMonitor.updateInputWindowsLw(true);
                }
            }
        });
    }
}

16 Source : SearchManagerService.java
with Apache License 2.0
from lulululbj

@Override
public boolean launchLegacyreplacedist(String hint, int userHandle, Bundle args) {
    ComponentName comp = getLegacyreplacedistComponent(userHandle);
    if (comp == null) {
        return false;
    }
    long ident = Binder.clearCallingIdenreplacedy();
    try {
        Intent intent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
        intent.setComponent(comp);
        IActivityManager am = ActivityManager.getService();
        if (args != null) {
            args.putInt(Intent.EXTRA_KEY_EVENT, android.view.KeyEvent.KEYCODE_replacedIST);
        }
        intent.putExtras(args);
        return am.launchreplacedistIntent(intent, ActivityManager.replacedIST_CONTEXT_BASIC, hint, userHandle, args);
    } catch (RemoteException e) {
    } finally {
        Binder.restoreCallingIdenreplacedy(ident);
    }
    return true;
}

16 Source : AssistDataRequester.java
with Apache License 2.0
from lulululbj

/**
 * Helper clreplaced to asynchronously fetch the replacedist data and screenshot from the current running
 * activities. It manages received data and calls back to the owner when the owner is ready to
 * receive the data itself.
 */
public clreplaced replacedistDataRequester extends IreplacedistDataReceiver.Stub {

    public static final String KEY_RECEIVER_EXTRA_COUNT = "count";

    public static final String KEY_RECEIVER_EXTRA_INDEX = "index";

    private IActivityManager mService;

    private IWindowManager mWindowManager;

    private Context mContext;

    private AppOpsManager mAppOpsManager;

    private replacedistDataRequesterCallbacks mCallbacks;

    private Object mCallbacksLock;

    private int mRequestStructureAppOps;

    private int mRequestScreenshotAppOps;

    private boolean mCanceled;

    private int mPendingDataCount;

    private int mPendingScreenshotCount;

    private final ArrayList<Bundle> mreplacedistData = new ArrayList<>();

    private final ArrayList<Bitmap> mreplacedistScreenshot = new ArrayList<>();

    /**
     * Interface to handle the events from the fetcher.
     */
    public interface replacedistDataRequesterCallbacks {

        /**
         * @return whether the currently received replacedist data can be handled by the callbacks.
         */
        @GuardedBy("mCallbacksLock")
        boolean canHandleReceivedreplacedistDataLocked();

        /**
         * Called when we receive asynchronous replacedist data. This call is only made if the
         * {@param fetchData} argument to requestreplacedistData() is true, and if the current activity
         * allows replacedist data to be fetched.  In addition, the callback will be made with the
         * {@param mCallbacksLock} held, and only if {@link #canHandleReceivedreplacedistDataLocked()}
         * is true.
         */
        @GuardedBy("mCallbacksLock")
        void onreplacedistDataReceivedLocked(Bundle data, int activityIndex, int activityCount);

        /**
         * Called when we receive asynchronous replacedist screenshot. This call is only made if
         * {@param fetchScreenshot} argument to requestreplacedistData() is true, and if the current
         * activity allows replacedist data to be fetched.  In addition, the callback will be made with
         * the {@param mCallbacksLock} held, and only if
         * {@link #canHandleReceivedreplacedistDataLocked()} is true.
         */
        @GuardedBy("mCallbacksLock")
        void onreplacedistScreenshotReceivedLocked(Bitmap screenshot);

        /**
         * Called when there is no more pending replacedist data or screenshots for the last request.
         * If the request was canceled, then this callback will not be made. In addition, the
         * callback will be made with the {@param mCallbacksLock} held, and only if
         * {@link #canHandleReceivedreplacedistDataLocked()} is true.
         */
        @GuardedBy("mCallbacksLock")
        default void onreplacedistRequestCompleted() {
        // Do nothing
        }
    }

    /**
     * @param callbacks The callbacks to handle the asynchronous reply with the replacedist data.
     * @param callbacksLock The lock for the requester to hold when calling any of the
     *                     {@param callbacks}. The owner should also take care in locking
     *                     appropriately when calling into this requester.
     * @param requestStructureAppOps The app ops to check before requesting the replacedist structure
     * @param requestScreenshotAppOps The app ops to check before requesting the replacedist screenshot.
     *                                This can be {@link AppOpsManager#OP_NONE} to indicate that
     *                                screenshots should never be fetched.
     */
    public replacedistDataRequester(Context context, IActivityManager service, IWindowManager windowManager, AppOpsManager appOpsManager, replacedistDataRequesterCallbacks callbacks, Object callbacksLock, int requestStructureAppOps, int requestScreenshotAppOps) {
        mCallbacks = callbacks;
        mCallbacksLock = callbacksLock;
        mWindowManager = windowManager;
        mService = service;
        mContext = context;
        mAppOpsManager = appOpsManager;
        mRequestStructureAppOps = requestStructureAppOps;
        mRequestScreenshotAppOps = requestScreenshotAppOps;
    }

    /**
     * Request that replacedist data be loaded asynchronously. The resulting data will be provided
     * through the {@link replacedistDataRequesterCallbacks}.
     *
     * @param activityTokens the list of visible activities
     * @param fetchData whether or not to fetch the replacedist data, only applies if the caller is
     *     allowed to fetch the replacedist data, and the current activity allows replacedist data to be
     *     fetched from it
     * @param fetchScreenshot whether or not to fetch the screenshot, only applies if fetchData is
     *     true, the caller is allowed to fetch the replacedist data, and the current activity allows
     *     replacedist data to be fetched from it
     * @param allowFetchData to be joined with other checks, determines whether or not the requester
     *     is allowed to fetch the replacedist data
     * @param allowFetchScreenshot to be joined with other checks, determines whether or not the
     *     requester is allowed to fetch the replacedist screenshot
     */
    public void requestreplacedistData(List<IBinder> activityTokens, final boolean fetchData, final boolean fetchScreenshot, boolean allowFetchData, boolean allowFetchScreenshot, int callingUid, String callingPackage) {
        // TODO(b/34090158): Known issue, if the replacedist data is not allowed on the current activity,
        // then no replacedist data is requested for any of the other activities
        // Early exit if there are no activity to fetch for
        if (activityTokens.isEmpty()) {
            // No activities, just dispatch request-complete
            tryDispatchRequestComplete();
            return;
        }
        // Ensure that the current activity supports replacedist data
        boolean isreplacedistDataAllowed = false;
        try {
            isreplacedistDataAllowed = mService.isreplacedistDataAllowedOnCurrentActivity();
        } catch (RemoteException e) {
        // Should never happen
        }
        allowFetchData &= isreplacedistDataAllowed;
        allowFetchScreenshot &= fetchData && isreplacedistDataAllowed && (mRequestScreenshotAppOps != OP_NONE);
        mCanceled = false;
        mPendingDataCount = 0;
        mPendingScreenshotCount = 0;
        mreplacedistData.clear();
        mreplacedistScreenshot.clear();
        if (fetchData) {
            if (mAppOpsManager.checkOpNoThrow(mRequestStructureAppOps, callingUid, callingPackage) == MODE_ALLOWED && allowFetchData) {
                final int numActivities = activityTokens.size();
                for (int i = 0; i < numActivities; i++) {
                    IBinder topActivity = activityTokens.get(i);
                    try {
                        MetricsLogger.count(mContext, "replacedist_with_context", 1);
                        Bundle receiverExtras = new Bundle();
                        receiverExtras.putInt(KEY_RECEIVER_EXTRA_INDEX, i);
                        receiverExtras.putInt(KEY_RECEIVER_EXTRA_COUNT, numActivities);
                        if (mService.requestreplacedistContextExtras(replacedIST_CONTEXT_FULL, this, receiverExtras, topActivity, /* focused= */
                        i == 0, /* newSessionId= */
                        i == 0)) {
                            mPendingDataCount++;
                        } else if (i == 0) {
                            // Wasn't allowed... given that, let's not do the screenshot either.
                            if (mCallbacks.canHandleReceivedreplacedistDataLocked()) {
                                dispatchreplacedistDataReceived(null);
                            } else {
                                mreplacedistData.add(null);
                            }
                            allowFetchScreenshot = false;
                            break;
                        }
                    } catch (RemoteException e) {
                    // Can't happen
                    }
                }
            } else {
                // Wasn't allowed... given that, let's not do the screenshot either.
                if (mCallbacks.canHandleReceivedreplacedistDataLocked()) {
                    dispatchreplacedistDataReceived(null);
                } else {
                    mreplacedistData.add(null);
                }
                allowFetchScreenshot = false;
            }
        }
        if (fetchScreenshot) {
            if (mAppOpsManager.checkOpNoThrow(mRequestScreenshotAppOps, callingUid, callingPackage) == MODE_ALLOWED && allowFetchScreenshot) {
                try {
                    MetricsLogger.count(mContext, "replacedist_with_screen", 1);
                    mPendingScreenshotCount++;
                    mWindowManager.requestreplacedistScreenshot(this);
                } catch (RemoteException e) {
                // Can't happen
                }
            } else {
                if (mCallbacks.canHandleReceivedreplacedistDataLocked()) {
                    dispatchreplacedistScreenshotReceived(null);
                } else {
                    mreplacedistScreenshot.add(null);
                }
            }
        }
        // For the cases where we dispatch null data/screenshot due to permissions, just dispatch
        // request-complete after those are made
        tryDispatchRequestComplete();
    }

    /**
     * This call should only be made when the callbacks are capable of handling the received replacedist
     * data. The owner is also responsible for locking before calling this method.
     */
    public void processPendingreplacedistData() {
        flushPendingreplacedistData();
        tryDispatchRequestComplete();
    }

    private void flushPendingreplacedistData() {
        final int dataCount = mreplacedistData.size();
        for (int i = 0; i < dataCount; i++) {
            dispatchreplacedistDataReceived(mreplacedistData.get(i));
        }
        mreplacedistData.clear();
        final int screenshotsCount = mreplacedistScreenshot.size();
        for (int i = 0; i < screenshotsCount; i++) {
            dispatchreplacedistScreenshotReceived(mreplacedistScreenshot.get(i));
        }
        mreplacedistScreenshot.clear();
    }

    public int getPendingDataCount() {
        return mPendingDataCount;
    }

    public int getPendingScreenshotCount() {
        return mPendingScreenshotCount;
    }

    /**
     * Cancels the current request for the replacedist data.
     */
    public void cancel() {
        // Reset the pending data count, if we receive new replacedist data after this point, it will
        // be ignored
        mCanceled = true;
        mPendingDataCount = 0;
        mPendingScreenshotCount = 0;
        mreplacedistData.clear();
        mreplacedistScreenshot.clear();
    }

    @Override
    public void onHandlereplacedistData(Bundle data) {
        synchronized (mCallbacksLock) {
            if (mCanceled) {
                return;
            }
            mPendingDataCount--;
            if (mCallbacks.canHandleReceivedreplacedistDataLocked()) {
                // Process any pending data and dispatch the new data as well
                flushPendingreplacedistData();
                dispatchreplacedistDataReceived(data);
                tryDispatchRequestComplete();
            } else {
                // Queue up the data for processing later
                mreplacedistData.add(data);
            }
        }
    }

    @Override
    public void onHandlereplacedistScreenshot(Bitmap screenshot) {
        synchronized (mCallbacksLock) {
            if (mCanceled) {
                return;
            }
            mPendingScreenshotCount--;
            if (mCallbacks.canHandleReceivedreplacedistDataLocked()) {
                // Process any pending data and dispatch the new data as well
                flushPendingreplacedistData();
                dispatchreplacedistScreenshotReceived(screenshot);
                tryDispatchRequestComplete();
            } else {
                // Queue up the data for processing later
                mreplacedistScreenshot.add(screenshot);
            }
        }
    }

    private void dispatchreplacedistDataReceived(Bundle data) {
        int activityIndex = 0;
        int activityCount = 0;
        final Bundle receiverExtras = data != null ? data.getBundle(replacedIST_KEY_RECEIVER_EXTRAS) : null;
        if (receiverExtras != null) {
            activityIndex = receiverExtras.getInt(KEY_RECEIVER_EXTRA_INDEX);
            activityCount = receiverExtras.getInt(KEY_RECEIVER_EXTRA_COUNT);
        }
        mCallbacks.onreplacedistDataReceivedLocked(data, activityIndex, activityCount);
    }

    private void dispatchreplacedistScreenshotReceived(Bitmap screenshot) {
        mCallbacks.onreplacedistScreenshotReceivedLocked(screenshot);
    }

    private void tryDispatchRequestComplete() {
        if (mPendingDataCount == 0 && mPendingScreenshotCount == 0 && mreplacedistData.isEmpty() && mreplacedistScreenshot.isEmpty()) {
            mCallbacks.onreplacedistRequestCompleted();
        }
    }

    public void dump(String prefix, PrintWriter pw) {
        pw.print(prefix);
        pw.print("mPendingDataCount=");
        pw.println(mPendingDataCount);
        pw.print(prefix);
        pw.print("mreplacedistData=");
        pw.println(mreplacedistData);
        pw.print(prefix);
        pw.print("mPendingScreenshotCount=");
        pw.println(mPendingScreenshotCount);
        pw.print(prefix);
        pw.print("mreplacedistScreenshot=");
        pw.println(mreplacedistScreenshot);
    }
}

15 Source : ShellUiAutomatorBridge.java
with Mozilla Public License 2.0
from coolwho

public long getSystemLongPressTime() {
    long longPressTimeout = 2000;
    try {
        IContentProvider provider = null;
        Cursor cursor = null;
        IActivityManager activityManager = ActivityManagerNative.getDefault();
        String providerName = Settings.Secure.CONTENT_URI.getAuthority();
        IBinder token = new Binder();
        try {
            ContentProviderHolder holder = activityManager.getContentProviderExternal(providerName, UserHandle.USER_OWNER, token);
            if (holder == null) {
                throw new IllegalStateException("Could not find provider: " + providerName);
            }
            provider = holder.provider;
            cursor = provider.query(null, Settings.Secure.CONTENT_URI, new String[] { Settings.Secure.VALUE }, "name=?", new String[] { Settings.Secure.LONG_PRESS_TIMEOUT }, null, null);
            if (cursor.moveToFirst()) {
                longPressTimeout = cursor.getInt(0);
            }
        } finally {
            if (cursor != null) {
                cursor.close();
            }
            if (provider != null) {
                activityManager.removeContentProviderExternal(providerName, token);
            }
        }
    } catch (Throwable e) {
    }
    return longPressTimeout;
}

15 Source : GlobalUtil.java
with Mozilla Public License 2.0
from coolwho

public static void startActivity(Intent intent) {
    IActivityManager am = ActivityManagerNative.getDefault();
    Method[] methods = am.getClreplaced().getMethods();
    for (int i = 0; i < methods.length; i++) {
        if (methods[i].getName().equals("startActivity")) {
            if (methods[i].getParameterTypes().length == 10) {
                try {
                    methods[i].invoke(am, null, "android", intent, null, null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS, null, null);
                    break;
                } catch (Exception e) {
                }
            } else if (methods[i].getParameterTypes().length == 13) {
                try {
                    methods[i].invoke(am, null, intent, null, null, 0, null, null, 0, true, false, null, null, null);
                    break;
                } catch (Exception e) {
                }
            }
        }
    }
}

14 Source : ClipboardService.java
with Apache License 2.0
from lulululbj

/**
 * Implementation of the clipboard for copy and paste.
 */
public clreplaced ClipboardService extends SystemService {

    private static final String TAG = "ClipboardService";

    private static final boolean IS_EMULATOR = SystemProperties.getBoolean("ro.kernel.qemu", false);

    private final IActivityManager mAm;

    private final IUserManager mUm;

    private final PackageManager mPm;

    private final AppOpsManager mAppOps;

    private final IBinder mPermissionOwner;

    private HostClipboardMonitor mHostClipboardMonitor = null;

    private Thread mHostMonitorThread = null;

    private final SparseArray<PerUserClipboard> mClipboards = new SparseArray<>();

    /**
     * Instantiates the clipboard.
     */
    public ClipboardService(Context context) {
        super(context);
        mAm = ActivityManager.getService();
        mPm = getContext().getPackageManager();
        mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
        mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
        IBinder permOwner = null;
        try {
            permOwner = mAm.newUriPermissionOwner("clipboard");
        } catch (RemoteException e) {
            Slog.w("clipboard", "AM dead", e);
        }
        mPermissionOwner = permOwner;
        if (IS_EMULATOR) {
            mHostClipboardMonitor = new HostClipboardMonitor(new HostClipboardMonitor.HostClipboardCallback() {

                @Override
                public void onHostClipboardUpdated(String contents) {
                    ClipData clip = new ClipData("host clipboard", new String[] { "text/plain" }, new ClipData.Item(contents));
                    synchronized (mClipboards) {
                        setPrimaryClipInternal(getClipboard(0), clip, android.os.Process.SYSTEM_UID);
                    }
                }
            });
            mHostMonitorThread = new Thread(mHostClipboardMonitor);
            mHostMonitorThread.start();
        }
    }

    @Override
    public void onStart() {
        publishBinderService(Context.CLIPBOARD_SERVICE, new ClipboardImpl());
    }

    @Override
    public void onCleanupUser(int userId) {
        synchronized (mClipboards) {
            mClipboards.remove(userId);
        }
    }

    private clreplaced ListenerInfo {

        final int mUid;

        final String mPackageName;

        ListenerInfo(int uid, String packageName) {
            mUid = uid;
            mPackageName = packageName;
        }
    }

    private clreplaced PerUserClipboard {

        final int userId;

        final RemoteCallbackList<IOnPrimaryClipChangedListener> primaryClipListeners = new RemoteCallbackList<IOnPrimaryClipChangedListener>();

        /**
         * Current primary clip.
         */
        ClipData primaryClip;

        /**
         * UID that set {@link #primaryClip}.
         */
        int primaryClipUid = android.os.Process.NOBODY_UID;

        final HashSet<String> activePermissionOwners = new HashSet<String>();

        PerUserClipboard(int userId) {
            this.userId = userId;
        }
    }

    private clreplaced ClipboardImpl extends IClipboard.Stub {

        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            try {
                return super.onTransact(code, data, reply, flags);
            } catch (RuntimeException e) {
                if (!(e instanceof SecurityException)) {
                    Slog.wtf("clipboard", "Exception: ", e);
                }
                throw e;
            }
        }

        @Override
        public void setPrimaryClip(ClipData clip, String callingPackage) {
            synchronized (this) {
                if (clip == null || clip.gereplacedemCount() <= 0) {
                    throw new IllegalArgumentException("No items");
                }
                final int callingUid = Binder.getCallingUid();
                if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage, callingUid)) {
                    return;
                }
                checkDataOwnerLocked(clip, callingUid);
                setPrimaryClipInternal(clip, callingUid);
            }
        }

        @Override
        public void clearPrimaryClip(String callingPackage) {
            synchronized (this) {
                final int callingUid = Binder.getCallingUid();
                if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage, callingUid)) {
                    return;
                }
                setPrimaryClipInternal(null, callingUid);
            }
        }

        @Override
        public ClipData getPrimaryClip(String pkg) {
            synchronized (this) {
                if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, pkg, Binder.getCallingUid()) || isDeviceLocked()) {
                    return null;
                }
                addActiveOwnerLocked(Binder.getCallingUid(), pkg);
                return getClipboard().primaryClip;
            }
        }

        @Override
        public ClipDescription getPrimaryClipDescription(String callingPackage) {
            synchronized (this) {
                if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, Binder.getCallingUid()) || isDeviceLocked()) {
                    return null;
                }
                PerUserClipboard clipboard = getClipboard();
                return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null;
            }
        }

        @Override
        public boolean hasPrimaryClip(String callingPackage) {
            synchronized (this) {
                if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, Binder.getCallingUid()) || isDeviceLocked()) {
                    return false;
                }
                return getClipboard().primaryClip != null;
            }
        }

        @Override
        public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener, String callingPackage) {
            synchronized (this) {
                getClipboard().primaryClipListeners.register(listener, new ListenerInfo(Binder.getCallingUid(), callingPackage));
            }
        }

        @Override
        public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) {
            synchronized (this) {
                getClipboard().primaryClipListeners.unregister(listener);
            }
        }

        @Override
        public boolean hasClipboardText(String callingPackage) {
            synchronized (this) {
                if (!clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, callingPackage, Binder.getCallingUid()) || isDeviceLocked()) {
                    return false;
                }
                PerUserClipboard clipboard = getClipboard();
                if (clipboard.primaryClip != null) {
                    CharSequence text = clipboard.primaryClip.gereplacedemAt(0).getText();
                    return text != null && text.length() > 0;
                }
                return false;
            }
        }
    }

    private PerUserClipboard getClipboard() {
        return getClipboard(UserHandle.getCallingUserId());
    }

    private PerUserClipboard getClipboard(int userId) {
        synchronized (mClipboards) {
            PerUserClipboard puc = mClipboards.get(userId);
            if (puc == null) {
                puc = new PerUserClipboard(userId);
                mClipboards.put(userId, puc);
            }
            return puc;
        }
    }

    List<UserInfo> getRelatedProfiles(int userId) {
        final List<UserInfo> related;
        final long origId = Binder.clearCallingIdenreplacedy();
        try {
            related = mUm.getProfiles(userId, true);
        } catch (RemoteException e) {
            Slog.e(TAG, "Remote Exception calling UserManager: " + e);
            return null;
        } finally {
            Binder.restoreCallingIdenreplacedy(origId);
        }
        return related;
    }

    /**
     * Check if the user has the given restriction set. Default to true if error occured during
     * calling UserManager, so it fails safe.
     */
    private boolean hasRestriction(String restriction, int userId) {
        try {
            return mUm.hasUserRestriction(restriction, userId);
        } catch (RemoteException e) {
            Slog.e(TAG, "Remote Exception calling UserManager.getUserRestrictions: ", e);
            // Fails safe
            return true;
        }
    }

    void setPrimaryClipInternal(@Nullable ClipData clip, int callingUid) {
        // Push clipboard to host, if any
        if (mHostClipboardMonitor != null) {
            if (clip == null) {
                // Someone really wants the clipboard cleared, so push empty
                mHostClipboardMonitor.setHostClipboard("");
            } else if (clip.gereplacedemCount() > 0) {
                final CharSequence text = clip.gereplacedemAt(0).getText();
                if (text != null) {
                    mHostClipboardMonitor.setHostClipboard(text.toString());
                }
            }
        }
        // Update this user
        final int userId = UserHandle.getUserId(callingUid);
        setPrimaryClipInternal(getClipboard(userId), clip, callingUid);
        // Update related users
        List<UserInfo> related = getRelatedProfiles(userId);
        if (related != null) {
            int size = related.size();
            if (size > 1) {
                // Related profiles list include the current profile.
                final boolean canCopy = !hasRestriction(UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE, userId);
                // Copy clip data to related users if allowed. If disallowed, then remove
                // primary clip in related users to prevent pasting stale content.
                if (!canCopy) {
                    clip = null;
                } else {
                    // We want to fix the uris of the related user's clip without changing the
                    // uris of the current user's clip.
                    // So, copy the ClipData, and then copy all the items, so that nothing
                    // is shared in memmory.
                    clip = new ClipData(clip);
                    for (int i = clip.gereplacedemCount() - 1; i >= 0; i--) {
                        clip.sereplacedemAt(i, new ClipData.Item(clip.gereplacedemAt(i)));
                    }
                    clip.fixUrisLight(userId);
                }
                for (int i = 0; i < size; i++) {
                    int id = related.get(i).id;
                    if (id != userId) {
                        final boolean canCopyIntoProfile = !hasRestriction(UserManager.DISALLOW_SHARE_INTO_MANAGED_PROFILE, id);
                        if (canCopyIntoProfile) {
                            setPrimaryClipInternal(getClipboard(id), clip, callingUid);
                        }
                    }
                }
            }
        }
    }

    void setPrimaryClipInternal(PerUserClipboard clipboard, @Nullable ClipData clip, int callingUid) {
        revokeUris(clipboard);
        clipboard.activePermissionOwners.clear();
        if (clip == null && clipboard.primaryClip == null) {
            return;
        }
        clipboard.primaryClip = clip;
        if (clip != null) {
            clipboard.primaryClipUid = callingUid;
        } else {
            clipboard.primaryClipUid = android.os.Process.NOBODY_UID;
        }
        if (clip != null) {
            final ClipDescription description = clip.getDescription();
            if (description != null) {
                description.setTimestamp(System.currentTimeMillis());
            }
        }
        final long ident = Binder.clearCallingIdenreplacedy();
        final int n = clipboard.primaryClipListeners.beginBroadcast();
        try {
            for (int i = 0; i < n; i++) {
                try {
                    ListenerInfo li = (ListenerInfo) clipboard.primaryClipListeners.getBroadcastCookie(i);
                    if (clipboardAccessAllowed(AppOpsManager.OP_READ_CLIPBOARD, li.mPackageName, li.mUid)) {
                        clipboard.primaryClipListeners.getBroadcasreplacedem(i).dispatchPrimaryClipChanged();
                    }
                } catch (RemoteException e) {
                // The RemoteCallbackList will take care of removing
                // the dead object for us.
                }
            }
        } finally {
            clipboard.primaryClipListeners.finishBroadcast();
            Binder.restoreCallingIdenreplacedy(ident);
        }
    }

    private boolean isDeviceLocked() {
        int callingUserId = UserHandle.getCallingUserId();
        final long token = Binder.clearCallingIdenreplacedy();
        try {
            final KeyguardManager keyguardManager = getContext().getSystemService(KeyguardManager.clreplaced);
            return keyguardManager != null && keyguardManager.isDeviceLocked(callingUserId);
        } finally {
            Binder.restoreCallingIdenreplacedy(token);
        }
    }

    private final void checkUriOwnerLocked(Uri uri, int sourceUid) {
        if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()))
            return;
        final long ident = Binder.clearCallingIdenreplacedy();
        try {
            // This will throw SecurityException if caller can't grant
            mAm.checkGrantUriPermission(sourceUid, null, ContentProvider.getUriWithoutUserId(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION, ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
        } catch (RemoteException ignored) {
        // Ignored because we're in same process
        } finally {
            Binder.restoreCallingIdenreplacedy(ident);
        }
    }

    private final void checkItemOwnerLocked(ClipData.Item item, int uid) {
        if (item.getUri() != null) {
            checkUriOwnerLocked(item.getUri(), uid);
        }
        Intent intent = item.getIntent();
        if (intent != null && intent.getData() != null) {
            checkUriOwnerLocked(intent.getData(), uid);
        }
    }

    private final void checkDataOwnerLocked(ClipData data, int uid) {
        final int N = data.gereplacedemCount();
        for (int i = 0; i < N; i++) {
            checkItemOwnerLocked(data.gereplacedemAt(i), uid);
        }
    }

    private final void grantUriLocked(Uri uri, int sourceUid, String targetPkg, int targetUserId) {
        if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()))
            return;
        final long ident = Binder.clearCallingIdenreplacedy();
        try {
            mAm.grantUriPermissionFromOwner(mPermissionOwner, sourceUid, targetPkg, ContentProvider.getUriWithoutUserId(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION, ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)), targetUserId);
        } catch (RemoteException ignored) {
        // Ignored because we're in same process
        } finally {
            Binder.restoreCallingIdenreplacedy(ident);
        }
    }

    private final void granreplacedemLocked(ClipData.Item item, int sourceUid, String targetPkg, int targetUserId) {
        if (item.getUri() != null) {
            grantUriLocked(item.getUri(), sourceUid, targetPkg, targetUserId);
        }
        Intent intent = item.getIntent();
        if (intent != null && intent.getData() != null) {
            grantUriLocked(intent.getData(), sourceUid, targetPkg, targetUserId);
        }
    }

    private final void addActiveOwnerLocked(int uid, String pkg) {
        final IPackageManager pm = AppGlobals.getPackageManager();
        final int targetUserHandle = UserHandle.getCallingUserId();
        final long oldIdenreplacedy = Binder.clearCallingIdenreplacedy();
        try {
            PackageInfo pi = pm.getPackageInfo(pkg, 0, targetUserHandle);
            if (pi == null) {
                throw new IllegalArgumentException("Unknown package " + pkg);
            }
            if (!UserHandle.isSameApp(pi.applicationInfo.uid, uid)) {
                throw new SecurityException("Calling uid " + uid + " does not own package " + pkg);
            }
        } catch (RemoteException e) {
        // Can't happen; the package manager is in the same process
        } finally {
            Binder.restoreCallingIdenreplacedy(oldIdenreplacedy);
        }
        PerUserClipboard clipboard = getClipboard();
        if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) {
            final int N = clipboard.primaryClip.gereplacedemCount();
            for (int i = 0; i < N; i++) {
                granreplacedemLocked(clipboard.primaryClip.gereplacedemAt(i), clipboard.primaryClipUid, pkg, UserHandle.getUserId(uid));
            }
            clipboard.activePermissionOwners.add(pkg);
        }
    }

    private final void revokeUriLocked(Uri uri, int sourceUid) {
        if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()))
            return;
        final long ident = Binder.clearCallingIdenreplacedy();
        try {
            mAm.revokeUriPermissionFromOwner(mPermissionOwner, ContentProvider.getUriWithoutUserId(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION, ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
        } catch (RemoteException ignored) {
        // Ignored because we're in same process
        } finally {
            Binder.restoreCallingIdenreplacedy(ident);
        }
    }

    private final void revokeItemLocked(ClipData.Item item, int sourceUid) {
        if (item.getUri() != null) {
            revokeUriLocked(item.getUri(), sourceUid);
        }
        Intent intent = item.getIntent();
        if (intent != null && intent.getData() != null) {
            revokeUriLocked(intent.getData(), sourceUid);
        }
    }

    private final void revokeUris(PerUserClipboard clipboard) {
        if (clipboard.primaryClip == null) {
            return;
        }
        final int N = clipboard.primaryClip.gereplacedemCount();
        for (int i = 0; i < N; i++) {
            revokeItemLocked(clipboard.primaryClip.gereplacedemAt(i), clipboard.primaryClipUid);
        }
    }

    private boolean clipboardAccessAllowed(int op, String callingPackage, int callingUid) {
        // Check the AppOp.
        if (mAppOps.noteOp(op, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
            return false;
        }
        try {
            // Installed apps can access the clipboard at any time.
            if (!AppGlobals.getPackageManager().isInstantApp(callingPackage, UserHandle.getUserId(callingUid))) {
                return true;
            }
            // Instant apps can only access the clipboard if they are in the foreground.
            return mAm.isAppForeground(callingUid);
        } catch (RemoteException e) {
            Slog.e("clipboard", "Failed to get Instant App status for package " + callingPackage, e);
            return false;
        }
    }
}

14 Source : PluginManager.java
with Apache License 2.0
from didi

/**
 * hookSystemServices, but need to compatible with Android O in future.
 */
protected void hookSystemServices() {
    try {
        Singleton<IActivityManager> defaultSingleton;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            defaultSingleton = Reflector.on(ActivityManager.clreplaced).field("IActivityManagerSingleton").get();
        } else {
            defaultSingleton = Reflector.on(ActivityManagerNative.clreplaced).field("gDefault").get();
        }
        IActivityManager origin = defaultSingleton.get();
        IActivityManager activityManagerProxy = (IActivityManager) Proxy.newProxyInstance(mContext.getClreplacedLoader(), new Clreplaced[] { IActivityManager.clreplaced }, createActivityManagerProxy(origin));
        // Hook IActivityManager from ActivityManagerNative
        Reflector.with(defaultSingleton).field("mInstance").set(activityManagerProxy);
        if (defaultSingleton.get() == activityManagerProxy) {
            this.mActivityManager = activityManagerProxy;
            Log.d(TAG, "hookSystemServices succeed : " + mActivityManager);
        }
    } catch (Exception e) {
        Log.w(TAG, e);
    }
}

13 Source : PinnerService.java
with Apache License 2.0
from lulululbj

/**
 * <p>PinnerService pins important files for key processes in memory.</p>
 * <p>Files to pin are specified in the config_defaultPinnerServiceFiles
 * overlay.</p>
 * <p>Pin the default camera application if specified in config_pinnerCameraApp.</p>
 */
public final clreplaced PinnerService extends SystemService {

    private static final boolean DEBUG = false;

    private static final String TAG = "PinnerService";

    private static final String PIN_META_FILENAME = "pinlist.meta";

    private static final int PAGE_SIZE = (int) Os.sysconf(OsConstants._SC_PAGESIZE);

    private static final int MATCH_FLAGS = PackageManager.MATCH_DEFAULT_ONLY | PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;

    private static final int KEY_CAMERA = 0;

    private static final int KEY_HOME = 1;

    // 80MB max for camera app.
    private static final int MAX_CAMERA_PIN_SIZE = 80 * (1 << 20);

    // 6MB max for home app.
    private static final int MAX_HOME_PIN_SIZE = 6 * (1 << 20);

    @IntDef({ KEY_CAMERA, KEY_HOME })
    @Retention(RetentionPolicy.SOURCE)
    public @interface AppKey {
    }

    private final Context mContext;

    private final ActivityManagerInternal mAmInternal;

    private final IActivityManager mAm;

    private final UserManager mUserManager;

    /**
     * The list of the statically pinned files.
     */
    @GuardedBy("this")
    private final ArrayList<PinnedFile> mPinnedFiles = new ArrayList<>();

    /**
     * The list of the pinned apps. This is a map from {@link AppKey} to a pinned app.
     */
    @GuardedBy("this")
    private final ArrayMap<Integer, PinnedApp> mPinnedApps = new ArrayMap<>();

    /**
     * The list of the pinned apps that need to be repinned as soon as the all processes of a given
     * uid are no longer active. Note that with background dex opt, the new dex/vdex files are only
     * loaded into the processes once it restarts. So in case background dex opt recompiled these
     * files, we still need to keep the old ones pinned until the processes restart.
     * <p>
     * This is a map from uid to {@link AppKey}
     */
    @GuardedBy("this")
    private final ArrayMap<Integer, Integer> mPendingRepin = new ArrayMap<>();

    /**
     * A set of {@link AppKey} that are configured to be pinned.
     */
    private final ArraySet<Integer> mPinKeys = new ArraySet<>();

    private BinderService mBinderService;

    private PinnerHandler mPinnerHandler = null;

    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            // If an app has updated, update pinned files accordingly.
            if (Intent.ACTION_PACKAGE_REPLACED.equals(intent.getAction())) {
                Uri packageUri = intent.getData();
                String packageName = packageUri.getSchemeSpecificPart();
                ArraySet<String> updatedPackages = new ArraySet<>();
                updatedPackages.add(packageName);
                update(updatedPackages, true);
            }
        }
    };

    public PinnerService(Context context) {
        super(context);
        mContext = context;
        boolean shouldPinCamera = context.getResources().getBoolean(com.android.internal.R.bool.config_pinnerCameraApp);
        boolean shouldPinHome = context.getResources().getBoolean(com.android.internal.R.bool.config_pinnerHomeApp);
        if (shouldPinCamera) {
            mPinKeys.add(KEY_CAMERA);
        }
        if (shouldPinHome) {
            mPinKeys.add(KEY_HOME);
        }
        mPinnerHandler = new PinnerHandler(BackgroundThread.get().getLooper());
        mAmInternal = LocalServices.getService(ActivityManagerInternal.clreplaced);
        mAm = ActivityManager.getService();
        mUserManager = mContext.getSystemService(UserManager.clreplaced);
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
        filter.addDataScheme("package");
        mContext.registerReceiver(mBroadcastReceiver, filter);
        registerUidListener();
        registerUserSetupCompleteListener();
    }

    @Override
    public void onStart() {
        if (DEBUG) {
            Slog.i(TAG, "Starting PinnerService");
        }
        mBinderService = new BinderService();
        publishBinderService("pinner", mBinderService);
        publishLocalService(PinnerService.clreplaced, this);
        mPinnerHandler.obtainMessage(PinnerHandler.PIN_ONSTART_MSG).sendToTarget();
        sendPinAppsMessage(UserHandle.USER_SYSTEM);
    }

    /**
     * Repin apps on user switch.
     * <p>
     * If more than one user is using the device each user may set a different preference for the
     * individual apps. Make sure that user's preference is pinned into memory.
     */
    @Override
    public void onSwitchUser(int userHandle) {
        if (!mUserManager.isManagedProfile(userHandle)) {
            sendPinAppsMessage(userHandle);
        }
    }

    @Override
    public void onUnlockUser(int userHandle) {
        if (!mUserManager.isManagedProfile(userHandle)) {
            sendPinAppsMessage(userHandle);
        }
    }

    /**
     * Update the currently pinned files.
     * Specifically, this only updates pinning for the apps that need to be pinned.
     * The other files pinned in onStart will not need to be updated.
     */
    public void update(ArraySet<String> updatedPackages, boolean force) {
        int currentUser = ActivityManager.getCurrentUser();
        for (int i = mPinKeys.size() - 1; i >= 0; i--) {
            int key = mPinKeys.valueAt(i);
            ApplicationInfo info = getInfoForKey(key, currentUser);
            if (info != null && updatedPackages.contains(info.packageName)) {
                Slog.i(TAG, "Updating pinned files for " + info.packageName + " force=" + force);
                sendPinAppMessage(key, currentUser, force);
            }
        }
    }

    /**
     * Handler for on start pinning message
     */
    private void handlePinOnStart() {
        // Files to pin come from the overlay and can be specified per-device config
        String[] filesToPin = mContext.getResources().getStringArray(com.android.internal.R.array.config_defaultPinnerServiceFiles);
        // Continue trying to pin each file even if we fail to pin some of them
        for (String fileToPin : filesToPin) {
            PinnedFile pf = pinFile(fileToPin, Integer.MAX_VALUE, /*attemptPinIntrospection=*/
            false);
            if (pf == null) {
                Slog.e(TAG, "Failed to pin file = " + fileToPin);
                continue;
            }
            synchronized (this) {
                mPinnedFiles.add(pf);
            }
        }
    }

    /**
     * Registers a listener to repin the home app when user setup is complete, as the home intent
     * initially resolves to setup wizard, but once setup is complete, it will resolve to the
     * regular home app.
     */
    private void registerUserSetupCompleteListener() {
        Uri userSetupCompleteUri = Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE);
        mContext.getContentResolver().registerContentObserver(userSetupCompleteUri, false, new ContentObserver(null) {

            @Override
            public void onChange(boolean selfChange, Uri uri) {
                if (userSetupCompleteUri.equals(uri)) {
                    sendPinAppMessage(KEY_HOME, ActivityManager.getCurrentUser(), true);
                }
            }
        }, UserHandle.USER_ALL);
    }

    private void registerUidListener() {
        try {
            mAm.registerUidObserver(new IUidObserver.Stub() {

                @Override
                public void onUidGone(int uid, boolean disabled) throws RemoteException {
                    mPinnerHandler.sendMessage(PooledLambda.obtainMessage(PinnerService::handleUidGone, PinnerService.this, uid));
                }

                @Override
                public void onUidActive(int uid) throws RemoteException {
                    mPinnerHandler.sendMessage(PooledLambda.obtainMessage(PinnerService::handleUidActive, PinnerService.this, uid));
                }

                @Override
                public void onUidIdle(int uid, boolean disabled) throws RemoteException {
                }

                @Override
                public void onUidStateChanged(int uid, int procState, long procStateSeq) throws RemoteException {
                }

                @Override
                public void onUidCachedChanged(int uid, boolean cached) throws RemoteException {
                }
            }, UID_OBSERVER_GONE | UID_OBSERVER_ACTIVE, 0, "system");
        } catch (RemoteException e) {
            Slog.e(TAG, "Failed to register uid observer", e);
        }
    }

    private void handleUidGone(int uid) {
        updateActiveState(uid, false);
        int key;
        synchronized (this) {
            // In case we have a pending repin, repin now. See mPendingRepin for more information.
            key = mPendingRepin.getOrDefault(uid, -1);
            if (key == -1) {
                return;
            }
            mPendingRepin.remove(uid);
        }
        pinApp(key, ActivityManager.getCurrentUser(), false);
    }

    private void handleUidActive(int uid) {
        updateActiveState(uid, true);
    }

    private void updateActiveState(int uid, boolean active) {
        synchronized (this) {
            for (int i = mPinnedApps.size() - 1; i >= 0; i--) {
                PinnedApp app = mPinnedApps.valueAt(i);
                if (app.uid == uid) {
                    app.active = active;
                }
            }
        }
    }

    private void unpinApp(@AppKey int key) {
        ArrayList<PinnedFile> pinnedAppFiles;
        synchronized (this) {
            PinnedApp app = mPinnedApps.get(key);
            if (app == null) {
                return;
            }
            mPinnedApps.remove(key);
            pinnedAppFiles = new ArrayList<>(app.mFiles);
        }
        for (PinnedFile pinnedFile : pinnedAppFiles) {
            pinnedFile.close();
        }
    }

    private boolean isResolverActivity(ActivityInfo info) {
        return ResolverActivity.clreplaced.getName().equals(info.name);
    }

    private ApplicationInfo getCameraInfo(int userHandle) {
        Intent cameraIntent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
        ApplicationInfo info = getApplicationInfoForIntent(cameraIntent, userHandle, false);
        // If the STILL_IMAGE_CAMERA intent doesn't resolve, try the _SECURE intent.
        // We don't use _SECURE first because it will never get set on a device
        // without File-based Encryption. But if the user has only set the intent
        // before unlocking their device, we may still be able to identify their
        // preference using this intent.
        if (info == null) {
            cameraIntent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE);
            info = getApplicationInfoForIntent(cameraIntent, userHandle, false);
        }
        // If the _SECURE intent doesn't resolve, try the original intent but request
        // the system app for camera if there was more than one result.
        if (info == null) {
            cameraIntent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
            info = getApplicationInfoForIntent(cameraIntent, userHandle, true);
        }
        return info;
    }

    private ApplicationInfo getHomeInfo(int userHandle) {
        Intent intent = mAmInternal.getHomeIntent();
        return getApplicationInfoForIntent(intent, userHandle, false);
    }

    private ApplicationInfo getApplicationInfoForIntent(Intent intent, int userHandle, boolean defaultToSystemApp) {
        if (intent == null) {
            return null;
        }
        ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivityAsUser(intent, MATCH_FLAGS, userHandle);
        // If this intent can resolve to only one app, choose that one.
        // Otherwise, if we've requested to default to the system app, return it;
        // if we have not requested that default, return null if there's more than one option.
        // If there's more than one system app, return null since we don't know which to pick.
        if (resolveInfo == null) {
            return null;
        }
        if (!isResolverActivity(resolveInfo.activityInfo)) {
            return resolveInfo.activityInfo.applicationInfo;
        }
        if (defaultToSystemApp) {
            List<ResolveInfo> infoList = mContext.getPackageManager().queryIntentActivitiesAsUser(intent, MATCH_FLAGS, userHandle);
            ApplicationInfo systemAppInfo = null;
            for (ResolveInfo info : infoList) {
                if ((info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                    if (systemAppInfo == null) {
                        systemAppInfo = info.activityInfo.applicationInfo;
                    } else {
                        // If there's more than one system app, return null due to ambiguity.
                        return null;
                    }
                }
            }
            return systemAppInfo;
        }
        return null;
    }

    private void sendPinAppsMessage(int userHandle) {
        mPinnerHandler.sendMessage(PooledLambda.obtainMessage(PinnerService::pinApps, this, userHandle));
    }

    private void pinApps(int userHandle) {
        for (int i = mPinKeys.size() - 1; i >= 0; i--) {
            int key = mPinKeys.valueAt(i);
            pinApp(key, userHandle, true);
        }
    }

    /**
     * @see #pinApp(int, int, boolean)
     */
    private void sendPinAppMessage(int key, int userHandle, boolean force) {
        mPinnerHandler.sendMessage(PooledLambda.obtainMessage(PinnerService::pinApp, this, key, userHandle, force));
    }

    /**
     * Pins an app of a specific type {@code key}.
     *
     * @param force If false, this will not repin the app if it's currently active. See
     *              {@link #mPendingRepin}.
     */
    private void pinApp(int key, int userHandle, boolean force) {
        int uid = getUidForKey(key);
        // In case the app is currently active, don't repin until next process restart. See
        // mPendingRepin for more information.
        if (!force && uid != -1) {
            synchronized (this) {
                mPendingRepin.put(uid, key);
            }
            return;
        }
        unpinApp(key);
        ApplicationInfo info = getInfoForKey(key, userHandle);
        if (info != null) {
            pinApp(key, info);
        }
    }

    /**
     * Checks whether the pinned package with {@code key} is active or not.
     *
     * @return The uid of the pinned app, or {@code -1} otherwise.
     */
    private int getUidForKey(@AppKey int key) {
        synchronized (this) {
            PinnedApp existing = mPinnedApps.get(key);
            return existing != null && existing.active ? existing.uid : -1;
        }
    }

    /**
     * Retrieves the current application info for the given app type.
     *
     * @param key The app type to retrieve the info for.
     * @param userHandle The user id of the current user.
     */
    @Nullable
    private ApplicationInfo getInfoForKey(@AppKey int key, int userHandle) {
        switch(key) {
            case KEY_CAMERA:
                return getCameraInfo(userHandle);
            case KEY_HOME:
                return getHomeInfo(userHandle);
            default:
                return null;
        }
    }

    /**
     * @return The app type name for {@code key}.
     */
    private String getNameForKey(@AppKey int key) {
        switch(key) {
            case KEY_CAMERA:
                return "Camera";
            case KEY_HOME:
                return "Home";
            default:
                return null;
        }
    }

    /**
     * @return The maximum amount of bytes to be pinned for an app of type {@code key}.
     */
    private int getSizeLimitForKey(@AppKey int key) {
        switch(key) {
            case KEY_CAMERA:
                return MAX_CAMERA_PIN_SIZE;
            case KEY_HOME:
                return MAX_HOME_PIN_SIZE;
            default:
                return 0;
        }
    }

    /**
     * Pins an application.
     *
     * @param key The key of the app to pin.
     * @param appInfo The corresponding app info.
     */
    private void pinApp(@AppKey int key, @Nullable ApplicationInfo appInfo) {
        if (appInfo == null) {
            return;
        }
        PinnedApp pinnedApp = new PinnedApp(appInfo);
        synchronized (this) {
            mPinnedApps.put(key, pinnedApp);
        }
        // pin APK
        int pinSizeLimit = getSizeLimitForKey(key);
        String apk = appInfo.sourceDir;
        PinnedFile pf = pinFile(apk, pinSizeLimit, /*attemptPinIntrospection=*/
        true);
        if (pf == null) {
            Slog.e(TAG, "Failed to pin " + apk);
            return;
        }
        if (DEBUG) {
            Slog.i(TAG, "Pinned " + pf.fileName);
        }
        synchronized (this) {
            pinnedApp.mFiles.add(pf);
        }
        // determine the ABI from either ApplicationInfo or Build
        String arch = "arm";
        if (appInfo.primaryCpuAbi != null) {
            if (VMRuntime.is64BitAbi(appInfo.primaryCpuAbi)) {
                arch = arch + "64";
            }
        } else {
            if (VMRuntime.is64BitAbi(Build.SUPPORTED_ABIS[0])) {
                arch = arch + "64";
            }
        }
        // get the path to the odex or oat file
        String baseCodePath = appInfo.getBaseCodePath();
        String[] files = null;
        try {
            files = DexFile.getDexFileOutputPaths(baseCodePath, arch);
        } catch (IOException ioe) {
        }
        if (files == null) {
            return;
        }
        // not pinning the oat/odex is not a fatal error
        for (String file : files) {
            pf = pinFile(file, pinSizeLimit, /*attemptPinIntrospection=*/
            false);
            if (pf != null) {
                synchronized (this) {
                    pinnedApp.mFiles.add(pf);
                }
                if (DEBUG) {
                    Slog.i(TAG, "Pinned " + pf.fileName);
                }
            }
        }
    }

    /**
     * mlock length bytes of fileToPin in memory
     *
     * If attemptPinIntrospection is true, then treat the file to pin as a zip file and
     * look for a "pinlist.meta" file in the archive root directory. The structure of this
     * file is a PINLIST_META as described below:
     *
     * <pre>
     *   PINLIST_META: PIN_RANGE*
     *   PIN_RANGE: PIN_START PIN_LENGTH
     *   PIN_START: big endian i32: offset in bytes of pin region from file start
     *   PIN_LENGTH: big endian i32: length of pin region in bytes
     * </pre>
     *
     * (We use big endian because that's what DataInputStream is hardcoded to use.)
     *
     * If attemptPinIntrospection is false, then we use a single implicit PIN_RANGE of (0,
     * maxBytesToPin); that is, we attempt to pin the first maxBytesToPin bytes of the file.
     *
     * After we open a file, we march through the list of pin ranges and attempt to pin
     * each one, stopping after we've pinned maxBytesToPin bytes. (We may truncate the last
     * pinned range to fit.)  In this way, by choosing to emit certain PIN_RANGE pairs
     * before others, file generators can express pins in priority order, making most
     * effective use of the pinned-page quota.
     *
     * N.B. Each PIN_RANGE is clamped to the actual bounds of the file; all inputs have a
     * meaningful interpretation. Also, a range locking a single byte of a page locks the
     * whole page. Any truncated PIN_RANGE at EOF is ignored. Overlapping pinned entries
     * are legal, but each pin of a byte counts toward the pin quota regardless of whether
     * that byte has already been pinned, so the generator of PINLIST_META ought to ensure
     * that ranges are non-overlapping.
     *
     * @param fileToPin Path to file to pin
     * @param maxBytesToPin Maximum number of bytes to pin
     * @param attemptPinIntrospection If true, try to open file as a
     *   zip in order to extract the
     * @return Pinned memory resource owner thing or null on error
     */
    private static PinnedFile pinFile(String fileToPin, int maxBytesToPin, boolean attemptPinIntrospection) {
        ZipFile fileAsZip = null;
        InputStream pinRangeStream = null;
        try {
            if (attemptPinIntrospection) {
                fileAsZip = maybeOpenZip(fileToPin);
            }
            if (fileAsZip != null) {
                pinRangeStream = maybeOpenPinMetaInZip(fileAsZip, fileToPin);
            }
            Slog.d(TAG, "pinRangeStream: " + pinRangeStream);
            PinRangeSource pinRangeSource = (pinRangeStream != null) ? new PinRangeSourceStream(pinRangeStream) : new PinRangeSourceStatic(0, Integer.MAX_VALUE);
            return pinFileRanges(fileToPin, maxBytesToPin, pinRangeSource);
        } finally {
            safeClose(pinRangeStream);
            // Also closes any streams we've opened
            safeClose(fileAsZip);
        }
    }

    /**
     * Attempt to open a file as a zip file. On any sort of corruption, log, swallow the
     * error, and return null.
     */
    private static ZipFile maybeOpenZip(String fileName) {
        ZipFile zip = null;
        try {
            zip = new ZipFile(fileName);
        } catch (IOException ex) {
            Slog.w(TAG, String.format("could not open \"%s\" as zip: pinning as blob", fileName), ex);
        }
        return zip;
    }

    /**
     * Open a pin metadata file in the zip if one is present.
     *
     * @param zipFile Zip file to search
     * @return Open input stream or null on any error
     */
    private static InputStream maybeOpenPinMetaInZip(ZipFile zipFile, String fileName) {
        ZipEntry pinMetaEntry = zipFile.getEntry(PIN_META_FILENAME);
        InputStream pinMetaStream = null;
        if (pinMetaEntry != null) {
            try {
                pinMetaStream = zipFile.getInputStream(pinMetaEntry);
            } catch (IOException ex) {
                Slog.w(TAG, String.format("error reading pin metadata \"%s\": pinning as blob", fileName), ex);
            }
        }
        return pinMetaStream;
    }

    private static abstract clreplaced PinRangeSource {

        /**
         * Retrive a range to pin.
         *
         * @param outPinRange Receives the pin region
         * @return True if we filled in outPinRange or false if we're out of pin entries
         */
        abstract boolean read(PinRange outPinRange);
    }

    private static final clreplaced PinRangeSourceStatic extends PinRangeSource {

        private final int mPinStart;

        private final int mPinLength;

        private boolean mDone = false;

        PinRangeSourceStatic(int pinStart, int pinLength) {
            mPinStart = pinStart;
            mPinLength = pinLength;
        }

        @Override
        boolean read(PinRange outPinRange) {
            outPinRange.start = mPinStart;
            outPinRange.length = mPinLength;
            boolean done = mDone;
            mDone = true;
            return !done;
        }
    }

    private static final clreplaced PinRangeSourceStream extends PinRangeSource {

        private final DataInputStream mStream;

        private boolean mDone = false;

        PinRangeSourceStream(InputStream stream) {
            mStream = new DataInputStream(stream);
        }

        @Override
        boolean read(PinRange outPinRange) {
            if (!mDone) {
                try {
                    outPinRange.start = mStream.readInt();
                    outPinRange.length = mStream.readInt();
                } catch (IOException ex) {
                    mDone = true;
                }
            }
            return !mDone;
        }
    }

    /**
     * Helper for pinFile.
     *
     * @param fileToPin Name of file to pin
     * @param maxBytesToPin Maximum number of bytes to pin
     * @param pinRangeSource Read PIN_RANGE entries from this stream to tell us what bytes
     *   to pin.
     * @return PinnedFile or null on error
     */
    private static PinnedFile pinFileRanges(String fileToPin, int maxBytesToPin, PinRangeSource pinRangeSource) {
        FileDescriptor fd = new FileDescriptor();
        long address = -1;
        int mapSize = 0;
        try {
            int openFlags = (OsConstants.O_RDONLY | OsConstants.O_CLOEXEC | OsConstants.O_NOFOLLOW);
            fd = Os.open(fileToPin, openFlags, 0);
            mapSize = (int) Math.min(Os.fstat(fd).st_size, Integer.MAX_VALUE);
            address = Os.mmap(0, mapSize, OsConstants.PROT_READ, OsConstants.MAP_SHARED, fd, /*offset=*/
            0);
            PinRange pinRange = new PinRange();
            int bytesPinned = 0;
            // We pin at page granularity, so make sure the limit is page-aligned
            if (maxBytesToPin % PAGE_SIZE != 0) {
                maxBytesToPin -= maxBytesToPin % PAGE_SIZE;
            }
            while (bytesPinned < maxBytesToPin && pinRangeSource.read(pinRange)) {
                int pinStart = pinRange.start;
                int pinLength = pinRange.length;
                pinStart = clamp(0, pinStart, mapSize);
                pinLength = clamp(0, pinLength, mapSize - pinStart);
                pinLength = Math.min(maxBytesToPin - bytesPinned, pinLength);
                // mlock doesn't require the region to be page-aligned, but we snap the
                // lock region to page boundaries anyway so that we don't under-count
                // locking a single byte of a page as a charge of one byte even though the
                // OS will retain the whole page. Thanks to this adjustment, we slightly
                // over-count the pin charge of back-to-back pins touching the same page,
                // but better that than undercounting. Besides: nothing stops pin metafile
                // creators from making the actual regions page-aligned.
                pinLength += pinStart % PAGE_SIZE;
                pinStart -= pinStart % PAGE_SIZE;
                if (pinLength % PAGE_SIZE != 0) {
                    pinLength += PAGE_SIZE - pinLength % PAGE_SIZE;
                }
                pinLength = clamp(0, pinLength, maxBytesToPin - bytesPinned);
                if (pinLength > 0) {
                    if (DEBUG) {
                        Slog.d(TAG, String.format("pinning at %s %s bytes of %s", pinStart, pinLength, fileToPin));
                    }
                    Os.mlock(address + pinStart, pinLength);
                }
                bytesPinned += pinLength;
            }
            PinnedFile pinnedFile = new PinnedFile(address, mapSize, fileToPin, bytesPinned);
            // Ownership transferred
            address = -1;
            return pinnedFile;
        } catch (ErrnoException ex) {
            Slog.e(TAG, "Could not pin file " + fileToPin, ex);
            return null;
        } finally {
            safeClose(fd);
            if (address >= 0) {
                safeMunmap(address, mapSize);
            }
        }
    }

    private static int clamp(int min, int value, int max) {
        return Math.max(min, Math.min(value, max));
    }

    private static void safeMunmap(long address, long mapSize) {
        try {
            Os.munmap(address, mapSize);
        } catch (ErrnoException ex) {
            Slog.w(TAG, "ignoring error in unmap", ex);
        }
    }

    /**
     * Close FD, swallowing irrelevant errors.
     */
    private static void safeClose(@Nullable FileDescriptor fd) {
        if (fd != null && fd.valid()) {
            try {
                Os.close(fd);
            } catch (ErrnoException ex) {
                // Swallow the exception: non-EBADF errors in close(2)
                // indicate deferred paging write errors, which we
                // don't care about here. The underlying file
                // descriptor is always closed.
                if (ex.errno == OsConstants.EBADF) {
                    throw new replacedertionError(ex);
                }
            }
        }
    }

    /**
     * Close closeable thing, swallowing errors.
     */
    private static void safeClose(@Nullable Closeable thing) {
        if (thing != null) {
            try {
                thing.close();
            } catch (IOException ex) {
                Slog.w(TAG, "ignoring error closing resource: " + thing, ex);
            }
        }
    }

    private final clreplaced BinderService extends Binder {

        @Override
        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
            if (!DumpUtils.checkDumpPermission(mContext, TAG, pw))
                return;
            synchronized (PinnerService.this) {
                long totalSize = 0;
                for (PinnedFile pinnedFile : mPinnedFiles) {
                    pw.format("%s %s\n", pinnedFile.fileName, pinnedFile.bytesPinned);
                    totalSize += pinnedFile.bytesPinned;
                }
                pw.println();
                for (int key : mPinnedApps.keySet()) {
                    PinnedApp app = mPinnedApps.get(key);
                    pw.print(getNameForKey(key));
                    pw.print(" uid=");
                    pw.print(app.uid);
                    pw.print(" active=");
                    pw.print(app.active);
                    pw.println();
                    for (PinnedFile pf : mPinnedApps.get(key).mFiles) {
                        pw.print("  ");
                        pw.format("%s %s\n", pf.fileName, pf.bytesPinned);
                        totalSize += pf.bytesPinned;
                    }
                }
                pw.format("Total size: %s\n", totalSize);
                pw.println();
                if (!mPendingRepin.isEmpty()) {
                    pw.print("Pending repin: ");
                    for (int key : mPendingRepin.values()) {
                        pw.print(getNameForKey(key));
                        pw.print(' ');
                    }
                    pw.println();
                }
            }
        }
    }

    private static final clreplaced PinnedFile implements AutoCloseable {

        private long mAddress;

        final int mapSize;

        final String fileName;

        final int bytesPinned;

        PinnedFile(long address, int mapSize, String fileName, int bytesPinned) {
            mAddress = address;
            this.mapSize = mapSize;
            this.fileName = fileName;
            this.bytesPinned = bytesPinned;
        }

        @Override
        public void close() {
            if (mAddress >= 0) {
                safeMunmap(mAddress, mapSize);
                mAddress = -1;
            }
        }

        @Override
        public void finalize() {
            close();
        }
    }

    final static clreplaced PinRange {

        int start;

        int length;
    }

    /**
     * Represents an app that was pinned.
     */
    private final clreplaced PinnedApp {

        /**
         * The uid of the package being pinned. This stays constant while the package stays
         * installed.
         */
        final int uid;

        /**
         * Whether it is currently active, i.e. there is a running process from that package.
         */
        boolean active;

        /**
         * List of pinned files.
         */
        final ArrayList<PinnedFile> mFiles = new ArrayList<>();

        private PinnedApp(ApplicationInfo appInfo) {
            uid = appInfo.uid;
            active = mAmInternal.isUidActive(uid);
        }
    }

    final clreplaced PinnerHandler extends Handler {

        static final int PIN_ONSTART_MSG = 4001;

        public PinnerHandler(Looper looper) {
            super(looper, null, true);
        }

        @Override
        public void handleMessage(Message msg) {
            switch(msg.what) {
                case PIN_ONSTART_MSG:
                    {
                        handlePinOnStart();
                    }
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }
}

13 Source : AppStateTracker.java
with Apache License 2.0
from lulululbj

/**
 * Clreplaced to keep track of the information related to "force app standby", which includes:
 * - OP_RUN_ANY_IN_BACKGROUND for each package
 * - UID foreground/active state
 * - User+system power save whitelist
 * - Temporary power save whitelist
 * - Global "force all apps standby" mode enforced by battery saver.
 *
 * Test:
 *  atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
 */
public clreplaced AppStateTracker {

    private static final String TAG = "AppStateTracker";

    private static final boolean DEBUG = false;

    private final Object mLock = new Object();

    private final Context mContext;

    @VisibleForTesting
    static final int TARGET_OP = AppOpsManager.OP_RUN_ANY_IN_BACKGROUND;

    IActivityManager mIActivityManager;

    ActivityManagerInternal mActivityManagerInternal;

    AppOpsManager mAppOpsManager;

    IAppOpsService mAppOpsService;

    PowerManagerInternal mPowerManagerInternal;

    StandbyTracker mStandbyTracker;

    UsageStatsManagerInternal mUsageStatsManagerInternal;

    private final MyHandler mHandler;

    @VisibleForTesting
    FeatureFlagsObserver mFlagsObserver;

    /**
     * Pair of (uid (not user-id), packageName) with OP_RUN_ANY_IN_BACKGROUND *not* allowed.
     */
    @GuardedBy("mLock")
    final ArraySet<Pair<Integer, String>> mRunAnyRestrictedPackages = new ArraySet<>();

    /**
     * UIDs that are active.
     */
    @GuardedBy("mLock")
    final SparseBooleanArray mActiveUids = new SparseBooleanArray();

    /**
     * UIDs that are in the foreground.
     */
    @GuardedBy("mLock")
    final SparseBooleanArray mForegroundUids = new SparseBooleanArray();

    /**
     * System except-idle + user whitelist in the device idle controller.
     */
    @GuardedBy("mLock")
    private int[] mPowerWhitelistedAllAppIds = new int[0];

    /**
     * User whitelisted apps in the device idle controller.
     */
    @GuardedBy("mLock")
    private int[] mPowerWhitelistedUserAppIds = new int[0];

    @GuardedBy("mLock")
    private int[] mTempWhitelistedAppIds = mPowerWhitelistedAllAppIds;

    /**
     * Per-user packages that are in the EXEMPT bucket.
     */
    @GuardedBy("mLock")
    private final SparseSetArray<String> mExemptedPackages = new SparseSetArray<>();

    @GuardedBy("mLock")
    final ArraySet<Listener> mListeners = new ArraySet<>();

    @GuardedBy("mLock")
    boolean mStarted;

    /**
     * Only used for small battery use-case.
     */
    @GuardedBy("mLock")
    boolean mIsPluggedIn;

    @GuardedBy("mLock")
    boolean mBatterySaverEnabled;

    /**
     * True if the forced app standby is currently enabled
     */
    @GuardedBy("mLock")
    boolean mForceAllAppsStandby;

    /**
     * True if the forced app standby for small battery devices feature is enabled in settings
     */
    @GuardedBy("mLock")
    boolean mForceAllAppStandbyForSmallBattery;

    /**
     * True if the forced app standby feature is enabled in settings
     */
    @GuardedBy("mLock")
    boolean mForcedAppStandbyEnabled;

    interface Stats {

        int UID_FG_STATE_CHANGED = 0;

        int UID_ACTIVE_STATE_CHANGED = 1;

        int RUN_ANY_CHANGED = 2;

        int ALL_UNWHITELISTED = 3;

        int ALL_WHITELIST_CHANGED = 4;

        int TEMP_WHITELIST_CHANGED = 5;

        int EXEMPT_CHANGED = 6;

        int FORCE_ALL_CHANGED = 7;

        int FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8;

        int IS_UID_ACTIVE_CACHED = 9;

        int IS_UID_ACTIVE_RAW = 10;
    }

    private final StatLogger mStatLogger = new StatLogger(new String[] { "UID_FG_STATE_CHANGED", "UID_ACTIVE_STATE_CHANGED", "RUN_ANY_CHANGED", "ALL_UNWHITELISTED", "ALL_WHITELIST_CHANGED", "TEMP_WHITELIST_CHANGED", "EXEMPT_CHANGED", "FORCE_ALL_CHANGED", "FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED", "IS_UID_ACTIVE_CACHED", "IS_UID_ACTIVE_RAW" });

    @VisibleForTesting
    clreplaced FeatureFlagsObserver extends ContentObserver {

        FeatureFlagsObserver() {
            super(null);
        }

        void register() {
            mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED), false, this);
            mContext.getContentResolver().registerContentObserver(Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED), false, this);
        }

        boolean isForcedAppStandbyEnabled() {
            return injectGetGlobalSettingInt(Settings.Global.FORCED_APP_STANDBY_ENABLED, 1) == 1;
        }

        boolean isForcedAppStandbyForSmallBatteryEnabled() {
            return injectGetGlobalSettingInt(Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED, 0) == 1;
        }

        @Override
        public void onChange(boolean selfChange, Uri uri) {
            if (Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_ENABLED).equals(uri)) {
                final boolean enabled = isForcedAppStandbyEnabled();
                synchronized (mLock) {
                    if (mForcedAppStandbyEnabled == enabled) {
                        return;
                    }
                    mForcedAppStandbyEnabled = enabled;
                    if (DEBUG) {
                        Slog.d(TAG, "Forced app standby feature flag changed: " + mForcedAppStandbyEnabled);
                    }
                }
                mHandler.notifyForcedAppStandbyFeatureFlagChanged();
            } else if (Settings.Global.getUriFor(Settings.Global.FORCED_APP_STANDBY_FOR_SMALL_BATTERY_ENABLED).equals(uri)) {
                final boolean enabled = isForcedAppStandbyForSmallBatteryEnabled();
                synchronized (mLock) {
                    if (mForceAllAppStandbyForSmallBattery == enabled) {
                        return;
                    }
                    mForceAllAppStandbyForSmallBattery = enabled;
                    if (DEBUG) {
                        Slog.d(TAG, "Forced app standby for small battery feature flag changed: " + mForceAllAppStandbyForSmallBattery);
                    }
                    updateForceAllAppStandbyState();
                }
            } else {
                Slog.w(TAG, "Unexpected feature flag uri encountered: " + uri);
            }
        }
    }

    public static abstract clreplaced Listener {

        /**
         * This is called when the OP_RUN_ANY_IN_BACKGROUND appops changed for a package.
         */
        private void onRunAnyAppOpsChanged(AppStateTracker sender, int uid, @NonNull String packageName) {
            updateJobsForUidPackage(uid, packageName, sender.isUidActive(uid));
            if (!sender.areAlarmsRestricted(uid, packageName, /*allowWhileIdle=*/
            false)) {
                unblockAlarmsForUidPackage(uid, packageName);
            } else if (!sender.areAlarmsRestricted(uid, packageName, /*allowWhileIdle=*/
            true)) {
                // we need to deliver the allow-while-idle alarms for this uid, package
                unblockAllUnrestrictedAlarms();
            }
            if (!sender.isRunAnyInBackgroundAppOpsAllowed(uid, packageName)) {
                Slog.v(TAG, "Package " + packageName + "/" + uid + " toggled into fg service restriction");
                stopForegroundServicesForUidPackage(uid, packageName);
            }
        }

        /**
         * This is called when the foreground state changed for a UID.
         */
        private void onUidForegroundStateChanged(AppStateTracker sender, int uid) {
            onUidForeground(uid, sender.isUidInForeground(uid));
        }

        /**
         * This is called when the active/idle state changed for a UID.
         */
        private void onUidActiveStateChanged(AppStateTracker sender, int uid) {
            final boolean isActive = sender.isUidActive(uid);
            updateJobsForUid(uid, isActive);
            if (isActive) {
                unblockAlarmsForUid(uid);
            }
        }

        /**
         * This is called when an app-id(s) is removed from the power save whitelist.
         */
        private void onPowerSaveUnwhitelisted(AppStateTracker sender) {
            updateAllJobs();
            unblockAllUnrestrictedAlarms();
        }

        /**
         * This is called when the power save whitelist changes, excluding the
         * {@link #onPowerSaveUnwhitelisted} case.
         */
        private void onPowerSaveWhitelistedChanged(AppStateTracker sender) {
            updateAllJobs();
        }

        /**
         * This is called when the temp whitelist changes.
         */
        private void onTempPowerSaveWhitelistChanged(AppStateTracker sender) {
            // TODO This case happens rather frequently; consider optimizing and update jobs
            // only for affected app-ids.
            updateAllJobs();
        // Note when an app is just put in the temp whitelist, we do *not* drain pending alarms.
        }

        /**
         * This is called when the EXEMPT bucket is updated.
         */
        private void onExemptChanged(AppStateTracker sender) {
            // This doesn't happen very often, so just re-evaluate all jobs / alarms.
            updateAllJobs();
            unblockAllUnrestrictedAlarms();
        }

        /**
         * This is called when the global "force all apps standby" flag changes.
         */
        private void onForceAllAppsStandbyChanged(AppStateTracker sender) {
            updateAllJobs();
            if (!sender.isForceAllAppsStandbyEnabled()) {
                unblockAllUnrestrictedAlarms();
            }
        }

        /**
         * Called when the job restrictions for multiple UIDs might have changed, so the job
         * scheduler should re-evaluate all restrictions for all jobs.
         */
        public void updateAllJobs() {
        }

        /**
         * Called when the job restrictions for a UID might have changed, so the job
         * scheduler should re-evaluate all restrictions for all jobs.
         */
        public void updateJobsForUid(int uid, boolean isNowActive) {
        }

        /**
         * Called when the job restrictions for a UID - package might have changed, so the job
         * scheduler should re-evaluate all restrictions for all jobs.
         */
        public void updateJobsForUidPackage(int uid, String packageName, boolean isNowActive) {
        }

        /**
         * Called when an app goes into forced app standby and its foreground
         * services need to be removed from that state.
         */
        public void stopForegroundServicesForUidPackage(int uid, String packageName) {
        }

        /**
         * Called when the job restrictions for multiple UIDs might have changed, so the alarm
         * manager should re-evaluate all restrictions for all blocked jobs.
         */
        public void unblockAllUnrestrictedAlarms() {
        }

        /**
         * Called when all jobs for a specific UID are unblocked.
         */
        public void unblockAlarmsForUid(int uid) {
        }

        /**
         * Called when all alarms for a specific UID - package are unblocked.
         */
        public void unblockAlarmsForUidPackage(int uid, String packageName) {
        }

        /**
         * Called when a UID comes into the foreground or the background.
         *
         * @see #isUidInForeground(int)
         */
        public void onUidForeground(int uid, boolean foreground) {
        }
    }

    public AppStateTracker(Context context, Looper looper) {
        mContext = context;
        mHandler = new MyHandler(looper);
    }

    /**
     * Call it when the system is ready.
     */
    public void onSystemServicesReady() {
        synchronized (mLock) {
            if (mStarted) {
                return;
            }
            mStarted = true;
            mIActivityManager = Preconditions.checkNotNull(injectIActivityManager());
            mActivityManagerInternal = Preconditions.checkNotNull(injectActivityManagerInternal());
            mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager());
            mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService());
            mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal());
            mUsageStatsManagerInternal = Preconditions.checkNotNull(injectUsageStatsManagerInternal());
            mFlagsObserver = new FeatureFlagsObserver();
            mFlagsObserver.register();
            mForcedAppStandbyEnabled = mFlagsObserver.isForcedAppStandbyEnabled();
            mForceAllAppStandbyForSmallBattery = mFlagsObserver.isForcedAppStandbyForSmallBatteryEnabled();
            mStandbyTracker = new StandbyTracker();
            mUsageStatsManagerInternal.addAppIdleStateChangeListener(mStandbyTracker);
            try {
                mIActivityManager.registerUidObserver(new UidObserver(), ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE | ActivityManager.UID_OBSERVER_ACTIVE | ActivityManager.UID_OBSERVER_PROCSTATE, ActivityManager.PROCESS_STATE_UNKNOWN, null);
                mAppOpsService.starreplacedchingMode(TARGET_OP, null, new AppOpsWatcher());
            } catch (RemoteException e) {
            // shouldn't happen.
            }
            IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_USER_REMOVED);
            filter.addAction(Intent.ACTION_BATTERY_CHANGED);
            mContext.registerReceiver(new MyReceiver(), filter);
            refreshForcedAppStandbyUidPackagesLocked();
            mPowerManagerInternal.registerLowPowerModeObserver(ServiceType.FORCE_ALL_APPS_STANDBY, (state) -> {
                synchronized (mLock) {
                    mBatterySaverEnabled = state.batterySaverEnabled;
                    updateForceAllAppStandbyState();
                }
            });
            mBatterySaverEnabled = mPowerManagerInternal.getLowPowerState(ServiceType.FORCE_ALL_APPS_STANDBY).batterySaverEnabled;
            updateForceAllAppStandbyState();
        }
    }

    @VisibleForTesting
    AppOpsManager injectAppOpsManager() {
        return mContext.getSystemService(AppOpsManager.clreplaced);
    }

    @VisibleForTesting
    IAppOpsService injectIAppOpsService() {
        return IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));
    }

    @VisibleForTesting
    IActivityManager injectIActivityManager() {
        return ActivityManager.getService();
    }

    @VisibleForTesting
    ActivityManagerInternal injectActivityManagerInternal() {
        return LocalServices.getService(ActivityManagerInternal.clreplaced);
    }

    @VisibleForTesting
    PowerManagerInternal injectPowerManagerInternal() {
        return LocalServices.getService(PowerManagerInternal.clreplaced);
    }

    @VisibleForTesting
    UsageStatsManagerInternal injectUsageStatsManagerInternal() {
        return LocalServices.getService(UsageStatsManagerInternal.clreplaced);
    }

    @VisibleForTesting
    boolean isSmallBatteryDevice() {
        return ActivityManager.isSmallBatteryDevice();
    }

    @VisibleForTesting
    int injectGetGlobalSettingInt(String key, int def) {
        return Settings.Global.getInt(mContext.getContentResolver(), key, def);
    }

    /**
     * Update {@link #mRunAnyRestrictedPackages} with the current app ops state.
     */
    @GuardedBy("mLock")
    private void refreshForcedAppStandbyUidPackagesLocked() {
        mRunAnyRestrictedPackages.clear();
        final List<PackageOps> ops = mAppOpsManager.getPackagesForOps(new int[] { TARGET_OP });
        if (ops == null) {
            return;
        }
        final int size = ops.size();
        for (int i = 0; i < size; i++) {
            final AppOpsManager.PackageOps pkg = ops.get(i);
            final List<AppOpsManager.OpEntry> entries = ops.get(i).getOps();
            for (int j = 0; j < entries.size(); j++) {
                AppOpsManager.OpEntry ent = entries.get(j);
                if (ent.getOp() != TARGET_OP) {
                    continue;
                }
                if (ent.getMode() != AppOpsManager.MODE_ALLOWED) {
                    mRunAnyRestrictedPackages.add(Pair.create(pkg.getUid(), pkg.getPackageName()));
                }
            }
        }
    }

    private void updateForceAllAppStandbyState() {
        synchronized (mLock) {
            if (mForceAllAppStandbyForSmallBattery && isSmallBatteryDevice()) {
                toggleForceAllAppsStandbyLocked(!mIsPluggedIn);
            } else {
                toggleForceAllAppsStandbyLocked(mBatterySaverEnabled);
            }
        }
    }

    /**
     * Update {@link #mForceAllAppsStandby} and notifies the listeners.
     */
    @GuardedBy("mLock")
    private void toggleForceAllAppsStandbyLocked(boolean enable) {
        if (enable == mForceAllAppsStandby) {
            return;
        }
        mForceAllAppsStandby = enable;
        mHandler.notifyForceAllAppsStandbyChanged();
    }

    @GuardedBy("mLock")
    private int findForcedAppStandbyUidPackageIndexLocked(int uid, @NonNull String packageName) {
        final int size = mRunAnyRestrictedPackages.size();
        if (size > 8) {
            return mRunAnyRestrictedPackages.indexOf(Pair.create(uid, packageName));
        }
        for (int i = 0; i < size; i++) {
            final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i);
            if ((pair.first == uid) && packageName.equals(pair.second)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * @return whether a uid package-name pair is in mRunAnyRestrictedPackages.
     */
    @GuardedBy("mLock")
    boolean isRunAnyRestrictedLocked(int uid, @NonNull String packageName) {
        return findForcedAppStandbyUidPackageIndexLocked(uid, packageName) >= 0;
    }

    /**
     * Add to / remove from {@link #mRunAnyRestrictedPackages}.
     */
    @GuardedBy("mLock")
    boolean updateForcedAppStandbyUidPackageLocked(int uid, @NonNull String packageName, boolean restricted) {
        final int index = findForcedAppStandbyUidPackageIndexLocked(uid, packageName);
        final boolean wasRestricted = index >= 0;
        if (wasRestricted == restricted) {
            return false;
        }
        if (restricted) {
            mRunAnyRestrictedPackages.add(Pair.create(uid, packageName));
        } else {
            mRunAnyRestrictedPackages.removeAt(index);
        }
        return true;
    }

    private static boolean addUidToArray(SparseBooleanArray array, int uid) {
        if (UserHandle.isCore(uid)) {
            return false;
        }
        if (array.get(uid)) {
            return false;
        }
        array.put(uid, true);
        return true;
    }

    private static boolean removeUidFromArray(SparseBooleanArray array, int uid, boolean remove) {
        if (UserHandle.isCore(uid)) {
            return false;
        }
        if (!array.get(uid)) {
            return false;
        }
        if (remove) {
            array.delete(uid);
        } else {
            array.put(uid, false);
        }
        return true;
    }

    private final clreplaced UidObserver extends IUidObserver.Stub {

        @Override
        public void onUidStateChanged(int uid, int procState, long procStateSeq) {
            mHandler.onUidStateChanged(uid, procState);
        }

        @Override
        public void onUidActive(int uid) {
            mHandler.onUidActive(uid);
        }

        @Override
        public void onUidGone(int uid, boolean disabled) {
            mHandler.onUidGone(uid, disabled);
        }

        @Override
        public void onUidIdle(int uid, boolean disabled) {
            mHandler.onUidIdle(uid, disabled);
        }

        @Override
        public void onUidCachedChanged(int uid, boolean cached) {
        }
    }

    private final clreplaced AppOpsWatcher extends IAppOpsCallback.Stub {

        @Override
        public void opChanged(int op, int uid, String packageName) throws RemoteException {
            boolean restricted = false;
            try {
                restricted = mAppOpsService.checkOperation(TARGET_OP, uid, packageName) != AppOpsManager.MODE_ALLOWED;
            } catch (RemoteException e) {
            // Shouldn't happen
            }
            synchronized (mLock) {
                if (updateForcedAppStandbyUidPackageLocked(uid, packageName, restricted)) {
                    mHandler.notifyRunAnyAppOpsChanged(uid, packageName);
                }
            }
        }
    }

    private final clreplaced MyReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
                if (userId > 0) {
                    mHandler.doUserRemoved(userId);
                }
            } else if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
                synchronized (mLock) {
                    mIsPluggedIn = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0);
                }
                updateForceAllAppStandbyState();
            }
        }
    }

    final clreplaced StandbyTracker extends AppIdleStateChangeListener {

        @Override
        public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket, int reason) {
            if (DEBUG) {
                Slog.d(TAG, "onAppIdleStateChanged: " + packageName + " u" + userId + (idle ? " idle" : " active") + " " + bucket);
            }
            final boolean changed;
            if (bucket == UsageStatsManager.STANDBY_BUCKET_EXEMPTED) {
                changed = mExemptedPackages.add(userId, packageName);
            } else {
                changed = mExemptedPackages.remove(userId, packageName);
            }
            if (changed) {
                mHandler.notifyExemptChanged();
            }
        }

        @Override
        public void onParoleStateChanged(boolean isParoleOn) {
        }
    }

    private Listener[] cloneListeners() {
        synchronized (mLock) {
            return mListeners.toArray(new Listener[mListeners.size()]);
        }
    }

    private clreplaced MyHandler extends Handler {

        private static final int MSG_UID_ACTIVE_STATE_CHANGED = 0;

        private static final int MSG_UID_FG_STATE_CHANGED = 1;

        private static final int MSG_RUN_ANY_CHANGED = 3;

        private static final int MSG_ALL_UNWHITELISTED = 4;

        private static final int MSG_ALL_WHITELIST_CHANGED = 5;

        private static final int MSG_TEMP_WHITELIST_CHANGED = 6;

        private static final int MSG_FORCE_ALL_CHANGED = 7;

        private static final int MSG_USER_REMOVED = 8;

        private static final int MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 9;

        private static final int MSG_EXEMPT_CHANGED = 10;

        private static final int MSG_ON_UID_STATE_CHANGED = 11;

        private static final int MSG_ON_UID_ACTIVE = 12;

        private static final int MSG_ON_UID_GONE = 13;

        private static final int MSG_ON_UID_IDLE = 14;

        public MyHandler(Looper looper) {
            super(looper);
        }

        public void notifyUidActiveStateChanged(int uid) {
            obtainMessage(MSG_UID_ACTIVE_STATE_CHANGED, uid, 0).sendToTarget();
        }

        public void notifyUidForegroundStateChanged(int uid) {
            obtainMessage(MSG_UID_FG_STATE_CHANGED, uid, 0).sendToTarget();
        }

        public void notifyRunAnyAppOpsChanged(int uid, @NonNull String packageName) {
            obtainMessage(MSG_RUN_ANY_CHANGED, uid, 0, packageName).sendToTarget();
        }

        public void notifyAllUnwhitelisted() {
            removeMessages(MSG_ALL_UNWHITELISTED);
            obtainMessage(MSG_ALL_UNWHITELISTED).sendToTarget();
        }

        public void notifyAllWhitelistChanged() {
            removeMessages(MSG_ALL_WHITELIST_CHANGED);
            obtainMessage(MSG_ALL_WHITELIST_CHANGED).sendToTarget();
        }

        public void notifyTempWhitelistChanged() {
            removeMessages(MSG_TEMP_WHITELIST_CHANGED);
            obtainMessage(MSG_TEMP_WHITELIST_CHANGED).sendToTarget();
        }

        public void notifyForceAllAppsStandbyChanged() {
            removeMessages(MSG_FORCE_ALL_CHANGED);
            obtainMessage(MSG_FORCE_ALL_CHANGED).sendToTarget();
        }

        public void notifyForcedAppStandbyFeatureFlagChanged() {
            removeMessages(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED);
            obtainMessage(MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED).sendToTarget();
        }

        public void notifyExemptChanged() {
            removeMessages(MSG_EXEMPT_CHANGED);
            obtainMessage(MSG_EXEMPT_CHANGED).sendToTarget();
        }

        public void doUserRemoved(int userId) {
            obtainMessage(MSG_USER_REMOVED, userId, 0).sendToTarget();
        }

        public void onUidStateChanged(int uid, int procState) {
            obtainMessage(MSG_ON_UID_STATE_CHANGED, uid, procState).sendToTarget();
        }

        public void onUidActive(int uid) {
            obtainMessage(MSG_ON_UID_ACTIVE, uid, 0).sendToTarget();
        }

        public void onUidGone(int uid, boolean disabled) {
            obtainMessage(MSG_ON_UID_GONE, uid, disabled ? 1 : 0).sendToTarget();
        }

        public void onUidIdle(int uid, boolean disabled) {
            obtainMessage(MSG_ON_UID_IDLE, uid, disabled ? 1 : 0).sendToTarget();
        }

        @Override
        public void handleMessage(Message msg) {
            switch(msg.what) {
                case MSG_USER_REMOVED:
                    handleUserRemoved(msg.arg1);
                    return;
            }
            // Only notify the listeners when started.
            synchronized (mLock) {
                if (!mStarted) {
                    return;
                }
            }
            final AppStateTracker sender = AppStateTracker.this;
            long start = mStatLogger.getTime();
            switch(msg.what) {
                case MSG_UID_ACTIVE_STATE_CHANGED:
                    for (Listener l : cloneListeners()) {
                        l.onUidActiveStateChanged(sender, msg.arg1);
                    }
                    mStatLogger.logDurationStat(Stats.UID_ACTIVE_STATE_CHANGED, start);
                    return;
                case MSG_UID_FG_STATE_CHANGED:
                    for (Listener l : cloneListeners()) {
                        l.onUidForegroundStateChanged(sender, msg.arg1);
                    }
                    mStatLogger.logDurationStat(Stats.UID_FG_STATE_CHANGED, start);
                    return;
                case MSG_RUN_ANY_CHANGED:
                    for (Listener l : cloneListeners()) {
                        l.onRunAnyAppOpsChanged(sender, msg.arg1, (String) msg.obj);
                    }
                    mStatLogger.logDurationStat(Stats.RUN_ANY_CHANGED, start);
                    return;
                case MSG_ALL_UNWHITELISTED:
                    for (Listener l : cloneListeners()) {
                        l.onPowerSaveUnwhitelisted(sender);
                    }
                    mStatLogger.logDurationStat(Stats.ALL_UNWHITELISTED, start);
                    return;
                case MSG_ALL_WHITELIST_CHANGED:
                    for (Listener l : cloneListeners()) {
                        l.onPowerSaveWhitelistedChanged(sender);
                    }
                    mStatLogger.logDurationStat(Stats.ALL_WHITELIST_CHANGED, start);
                    return;
                case MSG_TEMP_WHITELIST_CHANGED:
                    for (Listener l : cloneListeners()) {
                        l.onTempPowerSaveWhitelistChanged(sender);
                    }
                    mStatLogger.logDurationStat(Stats.TEMP_WHITELIST_CHANGED, start);
                    return;
                case MSG_EXEMPT_CHANGED:
                    for (Listener l : cloneListeners()) {
                        l.onExemptChanged(sender);
                    }
                    mStatLogger.logDurationStat(Stats.EXEMPT_CHANGED, start);
                    return;
                case MSG_FORCE_ALL_CHANGED:
                    for (Listener l : cloneListeners()) {
                        l.onForceAllAppsStandbyChanged(sender);
                    }
                    mStatLogger.logDurationStat(Stats.FORCE_ALL_CHANGED, start);
                    return;
                case MSG_FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED:
                    // Feature flag for forced app standby changed.
                    final boolean unblockAlarms;
                    synchronized (mLock) {
                        unblockAlarms = !mForcedAppStandbyEnabled && !mForceAllAppsStandby;
                    }
                    for (Listener l : cloneListeners()) {
                        l.updateAllJobs();
                        if (unblockAlarms) {
                            l.unblockAllUnrestrictedAlarms();
                        }
                    }
                    mStatLogger.logDurationStat(Stats.FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED, start);
                    return;
                case MSG_USER_REMOVED:
                    handleUserRemoved(msg.arg1);
                    return;
                case MSG_ON_UID_STATE_CHANGED:
                    handleUidStateChanged(msg.arg1, msg.arg2);
                    return;
                case MSG_ON_UID_ACTIVE:
                    handleUidActive(msg.arg1);
                    return;
                case MSG_ON_UID_GONE:
                    handleUidGone(msg.arg1, msg.arg1 != 0);
                    return;
                case MSG_ON_UID_IDLE:
                    handleUidIdle(msg.arg1, msg.arg1 != 0);
                    return;
            }
        }

        public void handleUidStateChanged(int uid, int procState) {
            synchronized (mLock) {
                if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
                    if (removeUidFromArray(mForegroundUids, uid, false)) {
                        mHandler.notifyUidForegroundStateChanged(uid);
                    }
                } else {
                    if (addUidToArray(mForegroundUids, uid)) {
                        mHandler.notifyUidForegroundStateChanged(uid);
                    }
                }
            }
        }

        public void handleUidActive(int uid) {
            synchronized (mLock) {
                if (addUidToArray(mActiveUids, uid)) {
                    mHandler.notifyUidActiveStateChanged(uid);
                }
            }
        }

        public void handleUidGone(int uid, boolean disabled) {
            removeUid(uid, true);
        }

        public void handleUidIdle(int uid, boolean disabled) {
            // Just to avoid excessive memcpy, don't remove from the array in this case.
            removeUid(uid, false);
        }

        private void removeUid(int uid, boolean remove) {
            synchronized (mLock) {
                if (removeUidFromArray(mActiveUids, uid, remove)) {
                    mHandler.notifyUidActiveStateChanged(uid);
                }
                if (removeUidFromArray(mForegroundUids, uid, remove)) {
                    mHandler.notifyUidForegroundStateChanged(uid);
                }
            }
        }
    }

    void handleUserRemoved(int removedUserId) {
        synchronized (mLock) {
            for (int i = mRunAnyRestrictedPackages.size() - 1; i >= 0; i--) {
                final Pair<Integer, String> pair = mRunAnyRestrictedPackages.valueAt(i);
                final int uid = pair.first;
                final int userId = UserHandle.getUserId(uid);
                if (userId == removedUserId) {
                    mRunAnyRestrictedPackages.removeAt(i);
                }
            }
            cleanUpArrayForUser(mActiveUids, removedUserId);
            cleanUpArrayForUser(mForegroundUids, removedUserId);
            mExemptedPackages.remove(removedUserId);
        }
    }

    private void cleanUpArrayForUser(SparseBooleanArray array, int removedUserId) {
        for (int i = array.size() - 1; i >= 0; i--) {
            final int uid = array.keyAt(i);
            final int userId = UserHandle.getUserId(uid);
            if (userId == removedUserId) {
                array.removeAt(i);
            }
        }
    }

    /**
     * Called by device idle controller to update the power save whitelists.
     */
    public void setPowerSaveWhitelistAppIds(int[] powerSaveWhitelistExceptIdleAppIdArray, int[] powerSaveWhitelistUserAppIdArray, int[] tempWhitelistAppIdArray) {
        synchronized (mLock) {
            final int[] previousWhitelist = mPowerWhitelistedAllAppIds;
            final int[] previousTempWhitelist = mTempWhitelistedAppIds;
            mPowerWhitelistedAllAppIds = powerSaveWhitelistExceptIdleAppIdArray;
            mTempWhitelistedAppIds = tempWhitelistAppIdArray;
            mPowerWhitelistedUserAppIds = powerSaveWhitelistUserAppIdArray;
            if (isAnyAppIdUnwhitelisted(previousWhitelist, mPowerWhitelistedAllAppIds)) {
                mHandler.notifyAllUnwhitelisted();
            } else if (!Arrays.equals(previousWhitelist, mPowerWhitelistedAllAppIds)) {
                mHandler.notifyAllWhitelistChanged();
            }
            if (!Arrays.equals(previousTempWhitelist, mTempWhitelistedAppIds)) {
                mHandler.notifyTempWhitelistChanged();
            }
        }
    }

    /**
     * @retunr true if a sorted app-id array {@code prevArray} has at least one element
     * that's not in a sorted app-id array {@code newArray}.
     */
    @VisibleForTesting
    static boolean isAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray) {
        int i1 = 0;
        int i2 = 0;
        boolean prevFinished;
        boolean newFinished;
        for (; ; ) {
            prevFinished = i1 >= prevArray.length;
            newFinished = i2 >= newArray.length;
            if (prevFinished || newFinished) {
                break;
            }
            int a1 = prevArray[i1];
            int a2 = newArray[i2];
            if (a1 == a2) {
                i1++;
                i2++;
                continue;
            }
            if (a1 < a2) {
                // prevArray has an element that's not in a2.
                return true;
            }
            i2++;
        }
        if (prevFinished) {
            return false;
        }
        return newFinished;
    }

    // Public interface.
    /**
     * Register a new listener.
     */
    public void addListener(@NonNull Listener listener) {
        synchronized (mLock) {
            mListeners.add(listener);
        }
    }

    /**
     * @return whether alarms should be restricted for a UID package-name.
     */
    public boolean areAlarmsRestricted(int uid, @NonNull String packageName, boolean isExemptOnBatterySaver) {
        return isRestricted(uid, packageName, /*useTempWhitelistToo=*/
        false, isExemptOnBatterySaver);
    }

    /**
     * @return whether jobs should be restricted for a UID package-name.
     */
    public boolean areJobsRestricted(int uid, @NonNull String packageName, boolean hasForegroundExemption) {
        return isRestricted(uid, packageName, /*useTempWhitelistToo=*/
        true, hasForegroundExemption);
    }

    /**
     * @return whether foreground services should be suppressed in the background
     * due to forced app standby for the given app
     */
    public boolean areForegroundServicesRestricted(int uid, @NonNull String packageName) {
        synchronized (mLock) {
            return isRunAnyRestrictedLocked(uid, packageName);
        }
    }

    /**
     * @return whether force-app-standby is effective for a UID package-name.
     */
    private boolean isRestricted(int uid, @NonNull String packageName, boolean useTempWhitelistToo, boolean exemptOnBatterySaver) {
        if (isUidActive(uid)) {
            return false;
        }
        synchronized (mLock) {
            // Whitelisted?
            final int appId = UserHandle.getAppId(uid);
            if (ArrayUtils.contains(mPowerWhitelistedAllAppIds, appId)) {
                return false;
            }
            if (useTempWhitelistToo && ArrayUtils.contains(mTempWhitelistedAppIds, appId)) {
                return false;
            }
            if (mForcedAppStandbyEnabled && isRunAnyRestrictedLocked(uid, packageName)) {
                return true;
            }
            if (exemptOnBatterySaver) {
                return false;
            }
            final int userId = UserHandle.getUserId(uid);
            if (mExemptedPackages.contains(userId, packageName)) {
                return false;
            }
            return mForceAllAppsStandby;
        }
    }

    /**
     * @return whether a UID is in active or not *based on cached information.*
     *
     * Note this information is based on the UID proc state callback, meaning it's updated
     * asynchronously and may subtly be stale. If the fresh data is needed, use
     * {@link #isUidActiveSynced} instead.
     */
    public boolean isUidActive(int uid) {
        if (UserHandle.isCore(uid)) {
            return true;
        }
        synchronized (mLock) {
            return mActiveUids.get(uid);
        }
    }

    /**
     * @return whether a UID is in active or not *right now.*
     *
     * This gives the fresh information, but may access the activity manager so is slower.
     */
    public boolean isUidActiveSynced(int uid) {
        if (isUidActive(uid)) {
            // Use the cached one first.
            return true;
        }
        final long start = mStatLogger.getTime();
        final boolean ret = mActivityManagerInternal.isUidActive(uid);
        mStatLogger.logDurationStat(Stats.IS_UID_ACTIVE_RAW, start);
        return ret;
    }

    /**
     * @return whether a UID is in the foreground or not.
     *
     * Note this information is based on the UID proc state callback, meaning it's updated
     * asynchronously and may subtly be stale. If the fresh data is needed, use
     * {@link ActivityManagerInternal#getUidProcessState} instead.
     */
    public boolean isUidInForeground(int uid) {
        if (UserHandle.isCore(uid)) {
            return true;
        }
        synchronized (mLock) {
            return mForegroundUids.get(uid);
        }
    }

    /**
     * @return whether force all apps standby is enabled or not.
     */
    boolean isForceAllAppsStandbyEnabled() {
        synchronized (mLock) {
            return mForceAllAppsStandby;
        }
    }

    /**
     * @return whether a UID/package has {@code OP_RUN_ANY_IN_BACKGROUND} allowed or not.
     *
     * Note clients normally shouldn't need to access it. It's only for dumpsys.
     */
    public boolean isRunAnyInBackgroundAppOpsAllowed(int uid, @NonNull String packageName) {
        synchronized (mLock) {
            return !isRunAnyRestrictedLocked(uid, packageName);
        }
    }

    /**
     * @return whether a UID is in the user / system defined power-save whitelist or not.
     *
     * Note clients normally shouldn't need to access it. It's only for dumpsys.
     */
    public boolean isUidPowerSaveWhitelisted(int uid) {
        synchronized (mLock) {
            return ArrayUtils.contains(mPowerWhitelistedAllAppIds, UserHandle.getAppId(uid));
        }
    }

    /**
     * @param uid the uid to check for
     * @return whether a UID is in the user defined power-save whitelist or not.
     */
    public boolean isUidPowerSaveUserWhitelisted(int uid) {
        synchronized (mLock) {
            return ArrayUtils.contains(mPowerWhitelistedUserAppIds, UserHandle.getAppId(uid));
        }
    }

    /**
     * @return whether a UID is in the temp power-save whitelist or not.
     *
     * Note clients normally shouldn't need to access it. It's only for dumpsys.
     */
    public boolean isUidTempPowerSaveWhitelisted(int uid) {
        synchronized (mLock) {
            return ArrayUtils.contains(mTempWhitelistedAppIds, UserHandle.getAppId(uid));
        }
    }

    @Deprecated
    public void dump(PrintWriter pw, String prefix) {
        dump(new IndentingPrintWriter(pw, "  ").setIndent(prefix));
    }

    public void dump(IndentingPrintWriter pw) {
        synchronized (mLock) {
            pw.println("Forced App Standby Feature enabled: " + mForcedAppStandbyEnabled);
            pw.print("Force all apps standby: ");
            pw.println(isForceAllAppsStandbyEnabled());
            pw.print("Small Battery Device: ");
            pw.println(isSmallBatteryDevice());
            pw.print("Force all apps standby for small battery device: ");
            pw.println(mForceAllAppStandbyForSmallBattery);
            pw.print("Plugged In: ");
            pw.println(mIsPluggedIn);
            pw.print("Active uids: ");
            dumpUids(pw, mActiveUids);
            pw.print("Foreground uids: ");
            dumpUids(pw, mForegroundUids);
            pw.print("Except-idle + user whitelist appids: ");
            pw.println(Arrays.toString(mPowerWhitelistedAllAppIds));
            pw.print("User whitelist appids: ");
            pw.println(Arrays.toString(mPowerWhitelistedUserAppIds));
            pw.print("Temp whitelist appids: ");
            pw.println(Arrays.toString(mTempWhitelistedAppIds));
            pw.println("Exempted packages:");
            pw.increaseIndent();
            for (int i = 0; i < mExemptedPackages.size(); i++) {
                pw.print("User ");
                pw.print(mExemptedPackages.keyAt(i));
                pw.println();
                pw.increaseIndent();
                for (int j = 0; j < mExemptedPackages.sizeAt(i); j++) {
                    pw.print(mExemptedPackages.valueAt(i, j));
                    pw.println();
                }
                pw.decreaseIndent();
            }
            pw.decreaseIndent();
            pw.println();
            pw.println("Restricted packages:");
            pw.increaseIndent();
            for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
                pw.print(UserHandle.formatUid(uidAndPackage.first));
                pw.print(" ");
                pw.print(uidAndPackage.second);
                pw.println();
            }
            pw.decreaseIndent();
            mStatLogger.dump(pw);
        }
    }

    private void dumpUids(PrintWriter pw, SparseBooleanArray array) {
        pw.print("[");
        String sep = "";
        for (int i = 0; i < array.size(); i++) {
            if (array.valueAt(i)) {
                pw.print(sep);
                pw.print(UserHandle.formatUid(array.keyAt(i)));
                sep = " ";
            }
        }
        pw.println("]");
    }

    public void dumpProto(ProtoOutputStream proto, long fieldId) {
        synchronized (mLock) {
            final long token = proto.start(fieldId);
            proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY, mForceAllAppsStandby);
            proto.write(ForceAppStandbyTrackerProto.IS_SMALL_BATTERY_DEVICE, isSmallBatteryDevice());
            proto.write(ForceAppStandbyTrackerProto.FORCE_ALL_APPS_STANDBY_FOR_SMALL_BATTERY, mForceAllAppStandbyForSmallBattery);
            proto.write(ForceAppStandbyTrackerProto.IS_PLUGGED_IN, mIsPluggedIn);
            for (int i = 0; i < mActiveUids.size(); i++) {
                if (mActiveUids.valueAt(i)) {
                    proto.write(ForceAppStandbyTrackerProto.ACTIVE_UIDS, mActiveUids.keyAt(i));
                }
            }
            for (int i = 0; i < mForegroundUids.size(); i++) {
                if (mForegroundUids.valueAt(i)) {
                    proto.write(ForceAppStandbyTrackerProto.FOREGROUND_UIDS, mForegroundUids.keyAt(i));
                }
            }
            for (int appId : mPowerWhitelistedAllAppIds) {
                proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_WHITELIST_APP_IDS, appId);
            }
            for (int appId : mPowerWhitelistedUserAppIds) {
                proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_USER_WHITELIST_APP_IDS, appId);
            }
            for (int appId : mTempWhitelistedAppIds) {
                proto.write(ForceAppStandbyTrackerProto.TEMP_POWER_SAVE_WHITELIST_APP_IDS, appId);
            }
            for (int i = 0; i < mExemptedPackages.size(); i++) {
                for (int j = 0; j < mExemptedPackages.sizeAt(i); j++) {
                    final long token2 = proto.start(ForceAppStandbyTrackerProto.EXEMPTED_PACKAGES);
                    proto.write(ExemptedPackage.USER_ID, mExemptedPackages.keyAt(i));
                    proto.write(ExemptedPackage.PACKAGE_NAME, mExemptedPackages.valueAt(i, j));
                    proto.end(token2);
                }
            }
            for (Pair<Integer, String> uidAndPackage : mRunAnyRestrictedPackages) {
                final long token2 = proto.start(ForceAppStandbyTrackerProto.RUN_ANY_IN_BACKGROUND_RESTRICTED_PACKAGES);
                proto.write(RunAnyInBackgroundRestrictedPackages.UID, uidAndPackage.first);
                proto.write(RunAnyInBackgroundRestrictedPackages.PACKAGE_NAME, uidAndPackage.second);
                proto.end(token2);
            }
            mStatLogger.dumpProto(proto, ForceAppStandbyTrackerProto.STATS);
            proto.end(token);
        }
    }
}

13 Source : LocalService.java
with Apache License 2.0
from didi

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (null == intent || !intent.hasExtra(EXTRA_TARGET) || !intent.hasExtra(EXTRA_COMMAND)) {
        return START_STICKY;
    }
    Intent target = intent.getParcelableExtra(EXTRA_TARGET);
    int command = intent.getIntExtra(EXTRA_COMMAND, 0);
    if (null == target || command <= 0) {
        return START_STICKY;
    }
    ComponentName component = target.getComponent();
    LoadedPlugin plugin = mPluginManager.getLoadedPlugin(component);
    if (plugin == null) {
        Log.w(TAG, "Error target: " + target.toURI());
        return START_STICKY;
    }
    // ClreplacedNotFoundException when unmarshalling in Android 5.1
    target.setExtrasClreplacedLoader(plugin.getClreplacedLoader());
    switch(command) {
        case EXTRA_COMMAND_START_SERVICE:
            {
                ActivityThread mainThread = ActivityThread.currentActivityThread();
                IApplicationThread appThread = mainThread.getApplicationThread();
                Service service;
                if (this.mPluginManager.getComponentsHandler().isServiceAvailable(component)) {
                    service = this.mPluginManager.getComponentsHandler().getService(component);
                } else {
                    try {
                        service = (Service) plugin.getClreplacedLoader().loadClreplaced(component.getClreplacedName()).newInstance();
                        Application app = plugin.getApplication();
                        IBinder token = appThread.asBinder();
                        Method attach = service.getClreplaced().getMethod("attach", Context.clreplaced, ActivityThread.clreplaced, String.clreplaced, IBinder.clreplaced, Application.clreplaced, Object.clreplaced);
                        IActivityManager am = mPluginManager.getActivityManager();
                        attach.invoke(service, plugin.getPluginContext(), mainThread, component.getClreplacedName(), token, app, am);
                        service.onCreate();
                        this.mPluginManager.getComponentsHandler().rememberService(component, service);
                    } catch (Throwable t) {
                        return START_STICKY;
                    }
                }
                service.onStartCommand(target, 0, this.mPluginManager.getComponentsHandler().getServiceCounter(service).getAndIncrement());
                break;
            }
        case EXTRA_COMMAND_BIND_SERVICE:
            {
                ActivityThread mainThread = ActivityThread.currentActivityThread();
                IApplicationThread appThread = mainThread.getApplicationThread();
                Service service = null;
                if (this.mPluginManager.getComponentsHandler().isServiceAvailable(component)) {
                    service = this.mPluginManager.getComponentsHandler().getService(component);
                } else {
                    try {
                        service = (Service) plugin.getClreplacedLoader().loadClreplaced(component.getClreplacedName()).newInstance();
                        Application app = plugin.getApplication();
                        IBinder token = appThread.asBinder();
                        Method attach = service.getClreplaced().getMethod("attach", Context.clreplaced, ActivityThread.clreplaced, String.clreplaced, IBinder.clreplaced, Application.clreplaced, Object.clreplaced);
                        IActivityManager am = mPluginManager.getActivityManager();
                        attach.invoke(service, plugin.getPluginContext(), mainThread, component.getClreplacedName(), token, app, am);
                        service.onCreate();
                        this.mPluginManager.getComponentsHandler().rememberService(component, service);
                    } catch (Throwable t) {
                        Log.w(TAG, t);
                    }
                }
                try {
                    IBinder binder = service.onBind(target);
                    IBinder serviceConnection = PluginUtil.getBinder(intent.getExtras(), "sc");
                    IServiceConnection iServiceConnection = IServiceConnection.Stub.asInterface(serviceConnection);
                    if (Build.VERSION.SDK_INT >= 26) {
                        iServiceConnection.connected(component, binder, false);
                    } else {
                        Reflector.QuietReflector.with(iServiceConnection).method("connected", ComponentName.clreplaced, IBinder.clreplaced).call(component, binder);
                    }
                } catch (Exception e) {
                    Log.w(TAG, e);
                }
                break;
            }
        case EXTRA_COMMAND_STOP_SERVICE:
            {
                Service service = this.mPluginManager.getComponentsHandler().forgetService(component);
                if (null != service) {
                    try {
                        service.onDestroy();
                    } catch (Exception e) {
                        Log.e(TAG, "Unable to stop service " + service + ": " + e.toString());
                    }
                } else {
                    Log.i(TAG, component + " not found");
                }
                break;
            }
        case EXTRA_COMMAND_UNBIND_SERVICE:
            {
                Service service = this.mPluginManager.getComponentsHandler().forgetService(component);
                if (null != service) {
                    try {
                        service.onUnbind(target);
                        service.onDestroy();
                    } catch (Exception e) {
                        Log.e(TAG, "Unable to unbind service " + service + ": " + e.toString());
                    }
                } else {
                    Log.i(TAG, component + " not found");
                }
                break;
            }
    }
    return START_STICKY;
}

12 Source : PluginManager.java
with Apache License 2.0
from didi

/**
 * Created by renyugang on 16/8/9.
 */
public clreplaced PluginManager {

    public static final String TAG = Constants.TAG_PREFIX + "PluginManager";

    private static volatile PluginManager sInstance = null;

    // Context of host app
    protected final Context mContext;

    protected final Application mApplication;

    protected ComponentsHandler mComponentsHandler;

    protected final Map<String, LoadedPlugin> mPlugins = new ConcurrentHashMap<>();

    protected final List<Callback> mCallbacks = new ArrayList<>();

    // Hooked instrumentation
    protected VAInstrumentation mInstrumentation;

    // Hooked IActivityManager binder
    protected IActivityManager mActivityManager;

    // Hooked IContentProvider binder
    protected IContentProvider mIContentProvider;

    public static PluginManager getInstance(Context base) {
        if (sInstance == null) {
            synchronized (PluginManager.clreplaced) {
                if (sInstance == null) {
                    sInstance = createInstance(base);
                }
            }
        }
        return sInstance;
    }

    private static PluginManager createInstance(Context context) {
        try {
            Bundle metaData = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA).metaData;
            if (metaData == null) {
                return new PluginManager(context);
            }
            String factoryClreplaced = metaData.getString("VA_FACTORY");
            if (factoryClreplaced == null) {
                return new PluginManager(context);
            }
            PluginManager pluginManager = Reflector.on(factoryClreplaced).method("create", Context.clreplaced).call(context);
            if (pluginManager != null) {
                Log.d(TAG, "Created a instance of " + pluginManager.getClreplaced());
                return pluginManager;
            }
        } catch (Exception e) {
            Log.w(TAG, "Created the instance error!", e);
        }
        return new PluginManager(context);
    }

    protected PluginManager(Context context) {
        if (context instanceof Application) {
            this.mApplication = (Application) context;
            this.mContext = mApplication.getBaseContext();
        } else {
            final Context app = context.getApplicationContext();
            if (app == null) {
                this.mContext = context;
                this.mApplication = ActivityThread.currentApplication();
            } else {
                this.mApplication = (Application) app;
                this.mContext = mApplication.getBaseContext();
            }
        }
        mComponentsHandler = createComponentsHandler();
        hookCurrentProcess();
    }

    protected void hookCurrentProcess() {
        hookInstrumentationAndHandler();
        hookSystemServices();
        hookDataBindingUtil();
    }

    public void init() {
        RunUtil.getThreadPool().execute(new Runnable() {

            @Override
            public void run() {
                doInWorkThread();
            }
        });
    }

    protected void doInWorkThread() {
    }

    public Application getHostApplication() {
        return this.mApplication;
    }

    protected ComponentsHandler createComponentsHandler() {
        return new ComponentsHandler(this);
    }

    protected VAInstrumentation createInstrumentation(Instrumentation origin) throws Exception {
        return new VAInstrumentation(this, origin);
    }

    protected ActivityManagerProxy createActivityManagerProxy(IActivityManager origin) throws Exception {
        return new ActivityManagerProxy(this, origin);
    }

    protected LoadedPlugin createLoadedPlugin(File apk) throws Exception {
        return new LoadedPlugin(this, this.mContext, apk);
    }

    protected void hookDataBindingUtil() {
        Reflector.QuietReflector reflector = Reflector.QuietReflector.on("android.databinding.DataBindingUtil").field("sMapper");
        Object old = reflector.get();
        if (old != null) {
            try {
                Callback callback = Reflector.on("android.databinding.DataBinderMapperProxy").constructor().newInstance();
                reflector.set(callback);
                addCallback(callback);
                Log.d(TAG, "hookDataBindingUtil succeed : " + callback);
            } catch (Reflector.ReflectedException e) {
                Log.w(TAG, e);
            }
        }
    }

    public void addCallback(Callback callback) {
        if (callback == null) {
            return;
        }
        synchronized (mCallbacks) {
            if (mCallbacks.contains(callback)) {
                throw new RuntimeException("Already added " + callback + "!");
            }
            mCallbacks.add(callback);
        }
    }

    public void removeCallback(Callback callback) {
        synchronized (mCallbacks) {
            mCallbacks.remove(callback);
        }
    }

    /**
     * hookSystemServices, but need to compatible with Android O in future.
     */
    protected void hookSystemServices() {
        try {
            Singleton<IActivityManager> defaultSingleton;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                defaultSingleton = Reflector.on(ActivityManager.clreplaced).field("IActivityManagerSingleton").get();
            } else {
                defaultSingleton = Reflector.on(ActivityManagerNative.clreplaced).field("gDefault").get();
            }
            IActivityManager origin = defaultSingleton.get();
            IActivityManager activityManagerProxy = (IActivityManager) Proxy.newProxyInstance(mContext.getClreplacedLoader(), new Clreplaced[] { IActivityManager.clreplaced }, createActivityManagerProxy(origin));
            // Hook IActivityManager from ActivityManagerNative
            Reflector.with(defaultSingleton).field("mInstance").set(activityManagerProxy);
            if (defaultSingleton.get() == activityManagerProxy) {
                this.mActivityManager = activityManagerProxy;
                Log.d(TAG, "hookSystemServices succeed : " + mActivityManager);
            }
        } catch (Exception e) {
            Log.w(TAG, e);
        }
    }

    protected void hookInstrumentationAndHandler() {
        try {
            ActivityThread activityThread = ActivityThread.currentActivityThread();
            Instrumentation baseInstrumentation = activityThread.getInstrumentation();
            // if (baseInstrumentation.getClreplaced().getName().contains("lbe")) {
            // // reject executing in paralell space, for example, lbe.
            // System.exit(0);
            // }
            final VAInstrumentation instrumentation = createInstrumentation(baseInstrumentation);
            Reflector.with(activityThread).field("mInstrumentation").set(instrumentation);
            Handler mainHandler = Reflector.with(activityThread).method("getHandler").call();
            Reflector.with(mainHandler).field("mCallback").set(instrumentation);
            this.mInstrumentation = instrumentation;
            Log.d(TAG, "hookInstrumentationAndHandler succeed : " + mInstrumentation);
        } catch (Exception e) {
            Log.w(TAG, e);
        }
    }

    protected void hookIContentProviderAsNeeded() {
        Uri uri = Uri.parse(RemoteContentProvider.getUri(mContext));
        mContext.getContentResolver().call(uri, "wakeup", null, null);
        try {
            Field authority = null;
            Field provider = null;
            ActivityThread activityThread = ActivityThread.currentActivityThread();
            Map providerMap = Reflector.with(activityThread).field("mProviderMap").get();
            Iterator iter = providerMap.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry entry = (Map.Entry) iter.next();
                Object key = entry.getKey();
                Object val = entry.getValue();
                String auth;
                if (key instanceof String) {
                    auth = (String) key;
                } else {
                    if (authority == null) {
                        authority = key.getClreplaced().getDeclaredField("authority");
                        authority.setAccessible(true);
                    }
                    auth = (String) authority.get(key);
                }
                if (auth.equals(RemoteContentProvider.getAuthority(mContext))) {
                    if (provider == null) {
                        provider = val.getClreplaced().getDeclaredField("mProvider");
                        provider.setAccessible(true);
                    }
                    IContentProvider rawProvider = (IContentProvider) provider.get(val);
                    IContentProvider proxy = IContentProviderProxy.newInstance(mContext, rawProvider);
                    mIContentProvider = proxy;
                    Log.d(TAG, "hookIContentProvider succeed : " + mIContentProvider);
                    break;
                }
            }
        } catch (Exception e) {
            Log.w(TAG, e);
        }
    }

    /**
     * load a plugin into memory, then invoke it's Application.
     * @param apk the file of plugin, should end with .apk
     * @throws Exception
     */
    public void loadPlugin(File apk) throws Exception {
        if (null == apk) {
            throw new IllegalArgumentException("error : apk is null.");
        }
        if (!apk.exists()) {
            // throw the FileNotFoundException by opening a stream.
            InputStream in = new FileInputStream(apk);
            in.close();
        }
        LoadedPlugin plugin = createLoadedPlugin(apk);
        if (null == plugin) {
            throw new RuntimeException("Can't load plugin which is invalid: " + apk.getAbsolutePath());
        }
        this.mPlugins.put(plugin.getPackageName(), plugin);
        synchronized (mCallbacks) {
            for (int i = 0; i < mCallbacks.size(); i++) {
                mCallbacks.get(i).onAddedLoadedPlugin(plugin);
            }
        }
    }

    public LoadedPlugin getLoadedPlugin(Intent intent) {
        return getLoadedPlugin(PluginUtil.getComponent(intent));
    }

    public LoadedPlugin getLoadedPlugin(ComponentName component) {
        if (component == null) {
            return null;
        }
        return this.getLoadedPlugin(component.getPackageName());
    }

    public LoadedPlugin getLoadedPlugin(String packageName) {
        return this.mPlugins.get(packageName);
    }

    public List<LoadedPlugin> getAllLoadedPlugins() {
        List<LoadedPlugin> list = new ArrayList<>();
        list.addAll(mPlugins.values());
        return list;
    }

    public Context getHostContext() {
        return this.mContext;
    }

    public VAInstrumentation getInstrumentation() {
        return this.mInstrumentation;
    }

    public IActivityManager getActivityManager() {
        return this.mActivityManager;
    }

    public synchronized IContentProvider getIContentProvider() {
        if (mIContentProvider == null) {
            hookIContentProviderAsNeeded();
        }
        return mIContentProvider;
    }

    public ComponentsHandler getComponentsHandler() {
        return mComponentsHandler;
    }

    public ResolveInfo resolveActivity(Intent intent) {
        return this.resolveActivity(intent, 0);
    }

    public ResolveInfo resolveActivity(Intent intent, int flags) {
        for (LoadedPlugin plugin : this.mPlugins.values()) {
            ResolveInfo resolveInfo = plugin.resolveActivity(intent, flags);
            if (null != resolveInfo) {
                return resolveInfo;
            }
        }
        return null;
    }

    public ResolveInfo resolveService(Intent intent, int flags) {
        for (LoadedPlugin plugin : this.mPlugins.values()) {
            ResolveInfo resolveInfo = plugin.resolveService(intent, flags);
            if (null != resolveInfo) {
                return resolveInfo;
            }
        }
        return null;
    }

    public ProviderInfo resolveContentProvider(String name, int flags) {
        for (LoadedPlugin plugin : this.mPlugins.values()) {
            ProviderInfo providerInfo = plugin.resolveContentProvider(name, flags);
            if (null != providerInfo) {
                return providerInfo;
            }
        }
        return null;
    }

    /**
     * used in PluginPackageManager, do not invoke it from outside.
     */
    @Deprecated
    public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
        List<ResolveInfo> resolveInfos = new ArrayList<ResolveInfo>();
        for (LoadedPlugin plugin : this.mPlugins.values()) {
            List<ResolveInfo> result = plugin.queryIntentActivities(intent, flags);
            if (null != result && result.size() > 0) {
                resolveInfos.addAll(result);
            }
        }
        return resolveInfos;
    }

    /**
     * used in PluginPackageManager, do not invoke it from outside.
     */
    @Deprecated
    public List<ResolveInfo> queryIntentServices(Intent intent, int flags) {
        List<ResolveInfo> resolveInfos = new ArrayList<ResolveInfo>();
        for (LoadedPlugin plugin : this.mPlugins.values()) {
            List<ResolveInfo> result = plugin.queryIntentServices(intent, flags);
            if (null != result && result.size() > 0) {
                resolveInfos.addAll(result);
            }
        }
        return resolveInfos;
    }

    /**
     * used in PluginPackageManager, do not invoke it from outside.
     */
    @Deprecated
    public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) {
        List<ResolveInfo> resolveInfos = new ArrayList<ResolveInfo>();
        for (LoadedPlugin plugin : this.mPlugins.values()) {
            List<ResolveInfo> result = plugin.queryBroadcastReceivers(intent, flags);
            if (null != result && result.size() > 0) {
                resolveInfos.addAll(result);
            }
        }
        return resolveInfos;
    }

    public interface Callback {

        void onAddedLoadedPlugin(LoadedPlugin plugin);
    }
}

9 Source : NotificationRecord.java
with Apache License 2.0
from lulululbj

/**
 * Holds data about notifications that should not be shared with the
 * {@link android.service.notification.NotificationListenerService}s.
 *
 * <p>These objects should not be mutated unless the code is synchronized
 * on {@link NotificationManagerService#mNotificationLock}, and any
 * modification should be followed by a sorting of that list.</p>
 *
 * <p>Is sortable by {@link NotificationComparator}.</p>
 *
 * {@hide}
 */
public final clreplaced NotificationRecord {

    static final String TAG = "NotificationRecord";

    static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);

    private static final int MAX_LOGTAG_LENGTH = 35;

    final StatusBarNotification sbn;

    IActivityManager mAm;

    final int mTargetSdkVersion;

    final int mOriginalFlags;

    private final Context mContext;

    NotificationUsageStats.SingleNotificationStats stats;

    boolean isCanceled;

    IBinder permissionOwner;

    // These members are used by NotificationSignalExtractors
    // to communicate with the ranking module.
    private float mContactAffinity;

    private boolean mRecentlyIntrusive;

    private long mLastIntrusive;

    // is this notification currently being intercepted by Zen Mode?
    private boolean mIntercept;

    // is this notification hidden since the app pkg is suspended?
    private boolean mHidden;

    // The timestamp used for ranking.
    private long mRankingTimeMs;

    // The first post time, stable across updates.
    private long mCreationTimeMs;

    // The most recent visibility event.
    private long mVisibleSinceMs;

    // The most recent update time, or the creation time if no updates.
    private long mUpdateTimeMs;

    // The most recent interruption time, or the creation time if no updates. Differs from the
    // above value because updates are filtered based on whether they actually interrupted the
    // user
    private long mInterruptionTimeMs;

    // Is this record an update of an old record?
    public boolean isUpdate;

    private int mPackagePriority;

    private int mAuthoritativeRank;

    private String mGlobalSortKey;

    private int mPackageVisibility;

    private int mUserImportance = IMPORTANCE_UNSPECIFIED;

    private int mImportance = IMPORTANCE_UNSPECIFIED;

    private CharSequence mImportanceExplanation = null;

    private int mSuppressedVisualEffects = 0;

    private String mUserExplanation;

    private String mPeopleExplanation;

    private boolean mPreChannelsNotification = true;

    private Uri mSound;

    private long[] mVibration;

    private AudioAttributes mAttributes;

    private NotificationChannel mChannel;

    private ArrayList<String> mPeopleOverride;

    private ArrayList<SnoozeCriterion> mSnoozeCriteria;

    private boolean mShowBadge;

    private LogMaker mLogMaker;

    private Light mLight;

    private String mGroupLogTag;

    private String mChannelIdLogTag;

    private final List<Adjustment> mAdjustments;

    private final NotificationStats mStats;

    private int mUserSentiment;

    private boolean mIsInterruptive;

    private boolean mTextChanged;

    private boolean mRecordedInterruption;

    private int mNumberOfSmartRepliesAdded;

    private boolean mHreplacedeenSmartReplies;

    /**
     * Whether this notification (and its channels) should be considered user locked. Used in
     * conjunction with user sentiment calculation.
     */
    private boolean mIsAppImportanceLocked;

    private ArraySet<Uri> mGrantableUris;

    public NotificationRecord(Context context, StatusBarNotification sbn, NotificationChannel channel) {
        this.sbn = sbn;
        mTargetSdkVersion = LocalServices.getService(PackageManagerInternal.clreplaced).getPackageTargetSdkVersion(sbn.getPackageName());
        mAm = ActivityManager.getService();
        mOriginalFlags = sbn.getNotification().flags;
        mRankingTimeMs = calculateRankingTimeMs(0L);
        mCreationTimeMs = sbn.getPostTime();
        mUpdateTimeMs = mCreationTimeMs;
        mInterruptionTimeMs = mCreationTimeMs;
        mContext = context;
        stats = new NotificationUsageStats.SingleNotificationStats();
        mChannel = channel;
        mPreChannelsNotification = isPreChannelsNotification();
        mSound = calculateSound();
        mVibration = calculateVibration();
        mAttributes = calculateAttributes();
        mImportance = calculateImportance();
        mLight = calculateLights();
        mAdjustments = new ArrayList<>();
        mStats = new NotificationStats();
        calculateUserSentiment();
        calculateGrantableUris();
    }

    private boolean isPreChannelsNotification() {
        if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(getChannel().getId())) {
            if (mTargetSdkVersion < Build.VERSION_CODES.O) {
                return true;
            }
        }
        return false;
    }

    private Uri calculateSound() {
        final Notification n = sbn.getNotification();
        // No notification sounds on tv
        if (mContext.getPackageManager().hreplacedystemFeature(PackageManager.FEATURE_LEANBACK)) {
            return null;
        }
        Uri sound = mChannel.getSound();
        if (mPreChannelsNotification && (getChannel().getUserLockedFields() & NotificationChannel.USER_LOCKED_SOUND) == 0) {
            final boolean useDefaultSound = (n.defaults & Notification.DEFAULT_SOUND) != 0;
            if (useDefaultSound) {
                sound = Settings.System.DEFAULT_NOTIFICATION_URI;
            } else {
                sound = n.sound;
            }
        }
        return sound;
    }

    private Light calculateLights() {
        int defaultLightColor = mContext.getResources().getColor(com.android.internal.R.color.config_defaultNotificationColor);
        int defaultLightOn = mContext.getResources().getInteger(com.android.internal.R.integer.config_defaultNotificationLedOn);
        int defaultLightOff = mContext.getResources().getInteger(com.android.internal.R.integer.config_defaultNotificationLedOff);
        int channelLightColor = getChannel().getLightColor() != 0 ? getChannel().getLightColor() : defaultLightColor;
        Light light = getChannel().shouldShowLights() ? new Light(channelLightColor, defaultLightOn, defaultLightOff) : null;
        if (mPreChannelsNotification && (getChannel().getUserLockedFields() & NotificationChannel.USER_LOCKED_LIGHTS) == 0) {
            final Notification notification = sbn.getNotification();
            if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) {
                light = new Light(notification.ledARGB, notification.ledOnMS, notification.ledOffMS);
                if ((notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
                    light = new Light(defaultLightColor, defaultLightOn, defaultLightOff);
                }
            } else {
                light = null;
            }
        }
        return light;
    }

    private long[] calculateVibration() {
        long[] vibration;
        final long[] defaultVibration = NotificationManagerService.getLongArray(mContext.getResources(), com.android.internal.R.array.config_defaultNotificationVibePattern, NotificationManagerService.VIBRATE_PATTERN_MAXLEN, NotificationManagerService.DEFAULT_VIBRATE_PATTERN);
        if (getChannel().shouldVibrate()) {
            vibration = getChannel().getVibrationPattern() == null ? defaultVibration : getChannel().getVibrationPattern();
        } else {
            vibration = null;
        }
        if (mPreChannelsNotification && (getChannel().getUserLockedFields() & NotificationChannel.USER_LOCKED_VIBRATION) == 0) {
            final Notification notification = sbn.getNotification();
            final boolean useDefaultVibrate = (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
            if (useDefaultVibrate) {
                vibration = defaultVibration;
            } else {
                vibration = notification.vibrate;
            }
        }
        return vibration;
    }

    private AudioAttributes calculateAttributes() {
        final Notification n = sbn.getNotification();
        AudioAttributes attributes = getChannel().getAudioAttributes();
        if (attributes == null) {
            attributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
        }
        if (mPreChannelsNotification && (getChannel().getUserLockedFields() & NotificationChannel.USER_LOCKED_SOUND) == 0) {
            if (n.audioAttributes != null) {
                // prefer audio attributes to stream type
                attributes = n.audioAttributes;
            } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
                // the stream type is valid, use it
                attributes = new AudioAttributes.Builder().setInternalLegacyStreamType(n.audioStreamType).build();
            } else if (n.audioStreamType != AudioSystem.STREAM_DEFAULT) {
                Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
            }
        }
        return attributes;
    }

    private int calculateImportance() {
        final Notification n = sbn.getNotification();
        int importance = getChannel().getImportance();
        int requestedImportance = IMPORTANCE_DEFAULT;
        // Migrate notification flags to scores
        if (0 != (n.flags & Notification.FLAG_HIGH_PRIORITY)) {
            n.priority = Notification.PRIORITY_MAX;
        }
        n.priority = NotificationManagerService.clamp(n.priority, Notification.PRIORITY_MIN, Notification.PRIORITY_MAX);
        switch(n.priority) {
            case Notification.PRIORITY_MIN:
                requestedImportance = IMPORTANCE_MIN;
                break;
            case Notification.PRIORITY_LOW:
                requestedImportance = IMPORTANCE_LOW;
                break;
            case Notification.PRIORITY_DEFAULT:
                requestedImportance = IMPORTANCE_DEFAULT;
                break;
            case Notification.PRIORITY_HIGH:
            case Notification.PRIORITY_MAX:
                requestedImportance = IMPORTANCE_HIGH;
                break;
        }
        stats.requestedImportance = requestedImportance;
        stats.isNoisy = mSound != null || mVibration != null;
        if (mPreChannelsNotification && (importance == IMPORTANCE_UNSPECIFIED || (getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0)) {
            if (!stats.isNoisy && requestedImportance > IMPORTANCE_LOW) {
                requestedImportance = IMPORTANCE_LOW;
            }
            if (stats.isNoisy) {
                if (requestedImportance < IMPORTANCE_DEFAULT) {
                    requestedImportance = IMPORTANCE_DEFAULT;
                }
            }
            if (n.fullScreenIntent != null) {
                requestedImportance = IMPORTANCE_HIGH;
            }
            importance = requestedImportance;
        }
        stats.naturalImportance = importance;
        return importance;
    }

    // copy any notes that the ranking system may have made before the update
    public void copyRankingInformation(NotificationRecord previous) {
        mContactAffinity = previous.mContactAffinity;
        mRecentlyIntrusive = previous.mRecentlyIntrusive;
        mPackagePriority = previous.mPackagePriority;
        mPackageVisibility = previous.mPackageVisibility;
        mIntercept = previous.mIntercept;
        mHidden = previous.mHidden;
        mRankingTimeMs = calculateRankingTimeMs(previous.getRankingTimeMs());
        mCreationTimeMs = previous.mCreationTimeMs;
        mVisibleSinceMs = previous.mVisibleSinceMs;
        if (previous.sbn.getOverrideGroupKey() != null && !sbn.isAppGroup()) {
            sbn.setOverrideGroupKey(previous.sbn.getOverrideGroupKey());
        }
    // Don't copy importance information or mGlobalSortKey, recompute them.
    }

    public Notification getNotification() {
        return sbn.getNotification();
    }

    public int getFlags() {
        return sbn.getNotification().flags;
    }

    public UserHandle getUser() {
        return sbn.getUser();
    }

    public String getKey() {
        return sbn.getKey();
    }

    /**
     * @deprecated Use {@link #getUser()} instead.
     */
    public int getUserId() {
        return sbn.getUserId();
    }

    public int getUid() {
        return sbn.getUid();
    }

    void dump(ProtoOutputStream proto, long fieldId, boolean redact, int state) {
        final long token = proto.start(fieldId);
        proto.write(NotificationRecordProto.KEY, sbn.getKey());
        proto.write(NotificationRecordProto.STATE, state);
        if (getChannel() != null) {
            proto.write(NotificationRecordProto.CHANNEL_ID, getChannel().getId());
        }
        proto.write(NotificationRecordProto.CAN_SHOW_LIGHT, getLight() != null);
        proto.write(NotificationRecordProto.CAN_VIBRATE, getVibration() != null);
        proto.write(NotificationRecordProto.FLAGS, sbn.getNotification().flags);
        proto.write(NotificationRecordProto.GROUP_KEY, getGroupKey());
        proto.write(NotificationRecordProto.IMPORTANCE, getImportance());
        if (getSound() != null) {
            proto.write(NotificationRecordProto.SOUND, getSound().toString());
        }
        if (getAudioAttributes() != null) {
            getAudioAttributes().writeToProto(proto, NotificationRecordProto.AUDIO_ATTRIBUTES);
        }
        proto.end(token);
    }

    String formatRemoteViews(RemoteViews rv) {
        if (rv == null)
            return "null";
        return String.format("%s/0x%08x (%d bytes): %s", rv.getPackage(), rv.getLayoutId(), rv.estimateMemoryUsage(), rv.toString());
    }

    void dump(PrintWriter pw, String prefix, Context baseContext, boolean redact) {
        final Notification notification = sbn.getNotification();
        final Icon icon = notification.getSmallIcon();
        String iconStr = String.valueOf(icon);
        if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
            iconStr += " / " + idDebugString(baseContext, icon.getResPackage(), icon.getResId());
        }
        pw.println(prefix + this);
        prefix = prefix + "  ";
        pw.println(prefix + "uid=" + sbn.getUid() + " userId=" + sbn.getUserId());
        pw.println(prefix + "icon=" + iconStr);
        pw.println(prefix + "flags=0x" + Integer.toHexString(notification.flags));
        pw.println(prefix + "pri=" + notification.priority);
        pw.println(prefix + "key=" + sbn.getKey());
        pw.println(prefix + "seen=" + mStats.hreplacedeen());
        pw.println(prefix + "groupKey=" + getGroupKey());
        pw.println(prefix + "fullscreenIntent=" + notification.fullScreenIntent);
        pw.println(prefix + "contentIntent=" + notification.contentIntent);
        pw.println(prefix + "deleteIntent=" + notification.deleteIntent);
        pw.print(prefix + "tickerText=");
        if (!TextUtils.isEmpty(notification.tickerText)) {
            final String ticker = notification.tickerText.toString();
            if (redact) {
                // if the string is long enough, we allow ourselves a few bytes for debugging
                pw.print(ticker.length() > 16 ? ticker.substring(0, 8) : "");
                pw.println("...");
            } else {
                pw.println(ticker);
            }
        } else {
            pw.println("null");
        }
        pw.println(prefix + "contentView=" + formatRemoteViews(notification.contentView));
        pw.println(prefix + "bigContentView=" + formatRemoteViews(notification.bigContentView));
        pw.println(prefix + "headsUpContentView=" + formatRemoteViews(notification.headsUpContentView));
        pw.print(prefix + String.format("color=0x%08x", notification.color));
        pw.println(prefix + "timeout=" + TimeUtils.formatForLogging(notification.getTimeoutAfter()));
        if (notification.actions != null && notification.actions.length > 0) {
            pw.println(prefix + "actions={");
            final int N = notification.actions.length;
            for (int i = 0; i < N; i++) {
                final Notification.Action action = notification.actions[i];
                if (action != null) {
                    pw.println(String.format("%s    [%d] \"%s\" -> %s", prefix, i, action.replacedle, action.actionIntent == null ? "null" : action.actionIntent.toString()));
                }
            }
            pw.println(prefix + "  }");
        }
        if (notification.extras != null && notification.extras.size() > 0) {
            pw.println(prefix + "extras={");
            for (String key : notification.extras.keySet()) {
                pw.print(prefix + "    " + key + "=");
                Object val = notification.extras.get(key);
                if (val == null) {
                    pw.println("null");
                } else {
                    pw.print(val.getClreplaced().getSimpleName());
                    if (redact && (val instanceof CharSequence || val instanceof String)) {
                    // redact contents from bugreports
                    } else if (val instanceof Bitmap) {
                        pw.print(String.format(" (%dx%d)", ((Bitmap) val).getWidth(), ((Bitmap) val).getHeight()));
                    } else if (val.getClreplaced().isArray()) {
                        final int N = Array.getLength(val);
                        pw.print(" (" + N + ")");
                        if (!redact) {
                            for (int j = 0; j < N; j++) {
                                pw.println();
                                pw.print(String.format("%s      [%d] %s", prefix, j, String.valueOf(Array.get(val, j))));
                            }
                        }
                    } else {
                        pw.print(" (" + String.valueOf(val) + ")");
                    }
                    pw.println();
                }
            }
            pw.println(prefix + "}");
        }
        pw.println(prefix + "stats=" + stats.toString());
        pw.println(prefix + "mContactAffinity=" + mContactAffinity);
        pw.println(prefix + "mRecentlyIntrusive=" + mRecentlyIntrusive);
        pw.println(prefix + "mPackagePriority=" + mPackagePriority);
        pw.println(prefix + "mPackageVisibility=" + mPackageVisibility);
        pw.println(prefix + "mUserImportance=" + NotificationListenerService.Ranking.importanceToString(mUserImportance));
        pw.println(prefix + "mImportance=" + NotificationListenerService.Ranking.importanceToString(mImportance));
        pw.println(prefix + "mImportanceExplanation=" + mImportanceExplanation);
        pw.println(prefix + "mIsAppImportanceLocked=" + mIsAppImportanceLocked);
        pw.println(prefix + "mIntercept=" + mIntercept);
        pw.println(prefix + "mHidden==" + mHidden);
        pw.println(prefix + "mGlobalSortKey=" + mGlobalSortKey);
        pw.println(prefix + "mRankingTimeMs=" + mRankingTimeMs);
        pw.println(prefix + "mCreationTimeMs=" + mCreationTimeMs);
        pw.println(prefix + "mVisibleSinceMs=" + mVisibleSinceMs);
        pw.println(prefix + "mUpdateTimeMs=" + mUpdateTimeMs);
        pw.println(prefix + "mInterruptionTimeMs=" + mInterruptionTimeMs);
        pw.println(prefix + "mSuppressedVisualEffects= " + mSuppressedVisualEffects);
        if (mPreChannelsNotification) {
            pw.println(prefix + String.format("defaults=0x%08x flags=0x%08x", notification.defaults, notification.flags));
            pw.println(prefix + "n.sound=" + notification.sound);
            pw.println(prefix + "n.audioStreamType=" + notification.audioStreamType);
            pw.println(prefix + "n.audioAttributes=" + notification.audioAttributes);
            pw.println(prefix + String.format("  led=0x%08x onMs=%d offMs=%d", notification.ledARGB, notification.ledOnMS, notification.ledOffMS));
            pw.println(prefix + "vibrate=" + Arrays.toString(notification.vibrate));
        }
        pw.println(prefix + "mSound= " + mSound);
        pw.println(prefix + "mVibration= " + mVibration);
        pw.println(prefix + "mAttributes= " + mAttributes);
        pw.println(prefix + "mLight= " + mLight);
        pw.println(prefix + "mShowBadge=" + mShowBadge);
        pw.println(prefix + "mColorized=" + notification.isColorized());
        pw.println(prefix + "mIsInterruptive=" + mIsInterruptive);
        pw.println(prefix + "effectiveNotificationChannel=" + getChannel());
        if (getPeopleOverride() != null) {
            pw.println(prefix + "overridePeople= " + TextUtils.join(",", getPeopleOverride()));
        }
        if (getSnoozeCriteria() != null) {
            pw.println(prefix + "snoozeCriteria=" + TextUtils.join(",", getSnoozeCriteria()));
        }
        pw.println(prefix + "mAdjustments=" + mAdjustments);
    }

    static String idDebugString(Context baseContext, String packageName, int id) {
        Context c;
        if (packageName != null) {
            try {
                c = baseContext.createPackageContext(packageName, 0);
            } catch (NameNotFoundException e) {
                c = baseContext;
            }
        } else {
            c = baseContext;
        }
        Resources r = c.getResources();
        try {
            return r.getResourceName(id);
        } catch (Resources.NotFoundException e) {
            return "<name unknown>";
        }
    }

    @Override
    public final String toString() {
        return String.format("NotificationRecord(0x%08x: pkg=%s user=%s id=%d tag=%s importance=%d key=%s" + "appImportanceLocked=%s: %s)", System.idenreplacedyHashCode(this), this.sbn.getPackageName(), this.sbn.getUser(), this.sbn.getId(), this.sbn.getTag(), this.mImportance, this.sbn.getKey(), mIsAppImportanceLocked, this.sbn.getNotification());
    }

    public void addAdjustment(Adjustment adjustment) {
        synchronized (mAdjustments) {
            mAdjustments.add(adjustment);
        }
    }

    public void applyAdjustments() {
        synchronized (mAdjustments) {
            for (Adjustment adjustment : mAdjustments) {
                Bundle signals = adjustment.getSignals();
                if (signals.containsKey(Adjustment.KEY_PEOPLE)) {
                    final ArrayList<String> people = adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
                    setPeopleOverride(people);
                }
                if (signals.containsKey(Adjustment.KEY_SNOOZE_CRITERIA)) {
                    final ArrayList<SnoozeCriterion> snoozeCriterionList = adjustment.getSignals().getParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA);
                    setSnoozeCriteria(snoozeCriterionList);
                }
                if (signals.containsKey(Adjustment.KEY_GROUP_KEY)) {
                    final String groupOverrideKey = adjustment.getSignals().getString(Adjustment.KEY_GROUP_KEY);
                    setOverrideGroupKey(groupOverrideKey);
                }
                if (signals.containsKey(Adjustment.KEY_USER_SENTIMENT)) {
                    // Only allow user sentiment update from replacedistant if user hasn't already
                    // expressed a preference for this channel
                    if (!mIsAppImportanceLocked && (getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0) {
                        setUserSentiment(adjustment.getSignals().getInt(Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEUTRAL));
                    }
                }
            }
        }
    }

    public void setIsAppImportanceLocked(boolean isAppImportanceLocked) {
        mIsAppImportanceLocked = isAppImportanceLocked;
        calculateUserSentiment();
    }

    public void setContactAffinity(float contactAffinity) {
        mContactAffinity = contactAffinity;
        if (mImportance < IMPORTANCE_DEFAULT && mContactAffinity > ValidateNotificationPeople.VALID_CONTACT) {
            setImportance(IMPORTANCE_DEFAULT, getPeopleExplanation());
        }
    }

    public float getContactAffinity() {
        return mContactAffinity;
    }

    public void setRecentlyIntrusive(boolean recentlyIntrusive) {
        mRecentlyIntrusive = recentlyIntrusive;
        if (recentlyIntrusive) {
            mLastIntrusive = System.currentTimeMillis();
        }
    }

    public boolean isRecentlyIntrusive() {
        return mRecentlyIntrusive;
    }

    public long getLastIntrusive() {
        return mLastIntrusive;
    }

    public void setPackagePriority(int packagePriority) {
        mPackagePriority = packagePriority;
    }

    public int getPackagePriority() {
        return mPackagePriority;
    }

    public void setPackageVisibilityOverride(int packageVisibility) {
        mPackageVisibility = packageVisibility;
    }

    public int getPackageVisibilityOverride() {
        return mPackageVisibility;
    }

    public void setUserImportance(int importance) {
        mUserImportance = importance;
        applyUserImportance();
    }

    private String getUserExplanation() {
        if (mUserExplanation == null) {
            mUserExplanation = mContext.getResources().getString(com.android.internal.R.string.importance_from_user);
        }
        return mUserExplanation;
    }

    private String getPeopleExplanation() {
        if (mPeopleExplanation == null) {
            mPeopleExplanation = mContext.getResources().getString(com.android.internal.R.string.importance_from_person);
        }
        return mPeopleExplanation;
    }

    private void applyUserImportance() {
        if (mUserImportance != IMPORTANCE_UNSPECIFIED) {
            mImportance = mUserImportance;
            mImportanceExplanation = getUserExplanation();
        }
    }

    public int getUserImportance() {
        return mUserImportance;
    }

    public void setImportance(int importance, CharSequence explanation) {
        if (importance != IMPORTANCE_UNSPECIFIED) {
            mImportance = importance;
            mImportanceExplanation = explanation;
        }
        applyUserImportance();
    }

    public int getImportance() {
        return mImportance;
    }

    public CharSequence getImportanceExplanation() {
        return mImportanceExplanation;
    }

    public boolean setIntercepted(boolean intercept) {
        mIntercept = intercept;
        return mIntercept;
    }

    public boolean isIntercepted() {
        return mIntercept;
    }

    public void setHidden(boolean hidden) {
        mHidden = hidden;
    }

    public boolean isHidden() {
        return mHidden;
    }

    public void setSuppressedVisualEffects(int effects) {
        mSuppressedVisualEffects = effects;
    }

    public int getSuppressedVisualEffects() {
        return mSuppressedVisualEffects;
    }

    public boolean isCategory(String category) {
        return Objects.equals(getNotification().category, category);
    }

    public boolean isAudioAttributesUsage(int usage) {
        return mAttributes != null && mAttributes.getUsage() == usage;
    }

    /**
     * Returns the timestamp to use for time-based sorting in the ranker.
     */
    public long getRankingTimeMs() {
        return mRankingTimeMs;
    }

    /**
     * @param now this current time in milliseconds.
     * @returns the number of milliseconds since the most recent update, or the post time if none.
     */
    public int getFreshnessMs(long now) {
        return (int) (now - mUpdateTimeMs);
    }

    /**
     * @param now this current time in milliseconds.
     * @returns the number of milliseconds since the the first post, ignoring updates.
     */
    public int getLifespanMs(long now) {
        return (int) (now - mCreationTimeMs);
    }

    /**
     * @param now this current time in milliseconds.
     * @returns the number of milliseconds since the most recent visibility event, or 0 if never.
     */
    public int getExposureMs(long now) {
        return mVisibleSinceMs == 0 ? 0 : (int) (now - mVisibleSinceMs);
    }

    public int getInterruptionMs(long now) {
        return (int) (now - mInterruptionTimeMs);
    }

    /**
     * Set the visibility of the notification.
     */
    public void setVisibility(boolean visible, int rank, int count) {
        final long now = System.currentTimeMillis();
        mVisibleSinceMs = visible ? now : mVisibleSinceMs;
        stats.onVisibilityChanged(visible);
        MetricsLogger.action(getLogMaker(now).setCategory(MetricsEvent.NOTIFICATION_ITEM).setType(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE).addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank).addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count));
        if (visible) {
            setSeen();
            MetricsLogger.histogram(mContext, "note_freshness", getFreshnessMs(now));
        }
        EventLogTags.writeNotificationVisibility(getKey(), visible ? 1 : 0, getLifespanMs(now), getFreshnessMs(now), // exposure time
        0, rank);
    }

    /**
     * @param previousRankingTimeMs for updated notifications, {@link #getRankingTimeMs()}
     *     of the previous notification record, 0 otherwise
     */
    private long calculateRankingTimeMs(long previousRankingTimeMs) {
        Notification n = getNotification();
        // Take developer provided 'when', unless it's in the future.
        if (n.when != 0 && n.when <= sbn.getPostTime()) {
            return n.when;
        }
        // If we've ranked a previous instance with a timestamp, inherit it. This case is
        // important in order to have ranking stability for updating notifications.
        if (previousRankingTimeMs > 0) {
            return previousRankingTimeMs;
        }
        return sbn.getPostTime();
    }

    public void setGlobalSortKey(String globalSortKey) {
        mGlobalSortKey = globalSortKey;
    }

    public String getGlobalSortKey() {
        return mGlobalSortKey;
    }

    /**
     * Check if any of the listeners have marked this notification as seen by the user.
     */
    public boolean isSeen() {
        return mStats.hreplacedeen();
    }

    /**
     * Mark the notification as seen by the user.
     */
    public void setSeen() {
        mStats.setSeen();
        if (mTextChanged) {
            setInterruptive(true);
        }
    }

    public void setAuthoritativeRank(int authoritativeRank) {
        mAuthoritativeRank = authoritativeRank;
    }

    public int getAuthoritativeRank() {
        return mAuthoritativeRank;
    }

    public String getGroupKey() {
        return sbn.getGroupKey();
    }

    public void setOverrideGroupKey(String overrideGroupKey) {
        sbn.setOverrideGroupKey(overrideGroupKey);
        mGroupLogTag = null;
    }

    private String getGroupLogTag() {
        if (mGroupLogTag == null) {
            mGroupLogTag = shortenTag(sbn.getGroup());
        }
        return mGroupLogTag;
    }

    private String getChannelIdLogTag() {
        if (mChannelIdLogTag == null) {
            mChannelIdLogTag = shortenTag(mChannel.getId());
        }
        return mChannelIdLogTag;
    }

    private String shortenTag(String longTag) {
        if (longTag == null) {
            return null;
        }
        if (longTag.length() < MAX_LOGTAG_LENGTH) {
            return longTag;
        } else {
            return longTag.substring(0, MAX_LOGTAG_LENGTH - 8) + "-" + Integer.toHexString(longTag.hashCode());
        }
    }

    public NotificationChannel getChannel() {
        return mChannel;
    }

    /**
     * @see RankingHelper#getIsAppImportanceLocked(String, int)
     */
    public boolean getIsAppImportanceLocked() {
        return mIsAppImportanceLocked;
    }

    protected void updateNotificationChannel(NotificationChannel channel) {
        if (channel != null) {
            mChannel = channel;
            calculateImportance();
            calculateUserSentiment();
        }
    }

    public void setShowBadge(boolean showBadge) {
        mShowBadge = showBadge;
    }

    public boolean canShowBadge() {
        return mShowBadge;
    }

    public Light getLight() {
        return mLight;
    }

    public Uri getSound() {
        return mSound;
    }

    public long[] getVibration() {
        return mVibration;
    }

    public AudioAttributes getAudioAttributes() {
        return mAttributes;
    }

    public ArrayList<String> getPeopleOverride() {
        return mPeopleOverride;
    }

    public void setInterruptive(boolean interruptive) {
        mIsInterruptive = interruptive;
        final long now = System.currentTimeMillis();
        mInterruptionTimeMs = interruptive ? now : mInterruptionTimeMs;
        if (interruptive) {
            MetricsLogger.action(getLogMaker().setCategory(MetricsEvent.NOTIFICATION_INTERRUPTION).setType(MetricsEvent.TYPE_OPEN).addTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS, getInterruptionMs(now)));
            MetricsLogger.histogram(mContext, "note_interruptive", getInterruptionMs(now));
        }
    }

    public void setTextChanged(boolean textChanged) {
        mTextChanged = textChanged;
    }

    public void setRecordedInterruption(boolean recorded) {
        mRecordedInterruption = recorded;
    }

    public boolean hasRecordedInterruption() {
        return mRecordedInterruption;
    }

    public boolean isInterruptive() {
        return mIsInterruptive;
    }

    protected void setPeopleOverride(ArrayList<String> people) {
        mPeopleOverride = people;
    }

    public ArrayList<SnoozeCriterion> getSnoozeCriteria() {
        return mSnoozeCriteria;
    }

    protected void setSnoozeCriteria(ArrayList<SnoozeCriterion> snoozeCriteria) {
        mSnoozeCriteria = snoozeCriteria;
    }

    private void calculateUserSentiment() {
        if ((getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0 || mIsAppImportanceLocked) {
            mUserSentiment = USER_SENTIMENT_POSITIVE;
        }
    }

    private void setUserSentiment(int userSentiment) {
        mUserSentiment = userSentiment;
    }

    public int getUserSentiment() {
        return mUserSentiment;
    }

    public NotificationStats getStats() {
        return mStats;
    }

    public void recordExpanded() {
        mStats.setExpanded();
    }

    public void recordDirectReplied() {
        mStats.setDirectReplied();
    }

    public void recordDismissalSurface(@NotificationStats.DismissalSurface int surface) {
        mStats.setDismissalSurface(surface);
    }

    public void recordSnoozed() {
        mStats.setSnoozed();
    }

    public void recordViewedSettings() {
        mStats.setViewedSettings();
    }

    public void setNumSmartRepliesAdded(int noReplies) {
        mNumberOfSmartRepliesAdded = noReplies;
    }

    public int getNumSmartRepliesAdded() {
        return mNumberOfSmartRepliesAdded;
    }

    public boolean hreplacedeenSmartReplies() {
        return mHreplacedeenSmartReplies;
    }

    public void setSeenSmartReplies(boolean hreplacedeenSmartReplies) {
        mHreplacedeenSmartReplies = hreplacedeenSmartReplies;
    }

    /**
     * @return all {@link Uri} that should have permission granted to whoever
     *         will be rendering it. This list has already been vetted to only
     *         include {@link Uri} that the enqueuing app can grant.
     */
    @Nullable
    public ArraySet<Uri> getGrantableUris() {
        return mGrantableUris;
    }

    /**
     * Collect all {@link Uri} that should have permission granted to whoever
     * will be rendering it.
     */
    protected void calculateGrantableUris() {
        final Notification notification = getNotification();
        notification.visitUris((uri) -> {
            visitGrantableUri(uri, false);
        });
        if (notification.getChannelId() != null) {
            NotificationChannel channel = getChannel();
            if (channel != null) {
                visitGrantableUri(channel.getSound(), (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_SOUND) != 0);
            }
        }
    }

    /**
     * Note the presence of a {@link Uri} that should have permission granted to
     * whoever will be rendering it.
     * <p>
     * If the enqueuing app has the ability to grant access, it will be added to
     * {@link #mGrantableUris}. Otherwise, this will either log or throw
     * {@link SecurityException} depending on target SDK of enqueuing app.
     */
    private void visitGrantableUri(Uri uri, boolean userOverriddenUri) {
        if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme()))
            return;
        // We can't grant Uri permissions from system
        final int sourceUid = sbn.getUid();
        if (sourceUid == android.os.Process.SYSTEM_UID)
            return;
        final long ident = Binder.clearCallingIdenreplacedy();
        try {
            // This will throw SecurityException if caller can't grant
            mAm.checkGrantUriPermission(sourceUid, null, ContentProvider.getUriWithoutUserId(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION, ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
            if (mGrantableUris == null) {
                mGrantableUris = new ArraySet<>();
            }
            mGrantableUris.add(uri);
        } catch (RemoteException ignored) {
        // Ignored because we're in same process
        } catch (SecurityException e) {
            if (!userOverriddenUri) {
                if (mTargetSdkVersion >= Build.VERSION_CODES.P) {
                    throw e;
                } else {
                    Log.w(TAG, "Ignoring " + uri + " from " + sourceUid + ": " + e.getMessage());
                }
            }
        } finally {
            Binder.restoreCallingIdenreplacedy(ident);
        }
    }

    public LogMaker getLogMaker(long now) {
        if (mLogMaker == null) {
            // initialize fields that only change on update (so a new record)
            mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN).setPackageName(sbn.getPackageName()).addTaggedData(MetricsEvent.NOTIFICATION_ID, sbn.getId()).addTaggedData(MetricsEvent.NOTIFICATION_TAG, sbn.getTag()).addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID, getChannelIdLogTag());
        }
        // reset fields that can change between updates, or are used by multiple logs
        return mLogMaker.clearCategory().clearType().clearSubtype().clearTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX).addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_IMPORTANCE, mImportance).addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID, getGroupLogTag()).addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_SUMMARY, sbn.getNotification().isGroupSummary() ? 1 : 0).addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, getLifespanMs(now)).addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS, getFreshnessMs(now)).addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, getExposureMs(now)).addTaggedData(MetricsEvent.NOTIFICATION_SINCE_INTERRUPTION_MILLIS, getInterruptionMs(now));
    }

    public LogMaker getLogMaker() {
        return getLogMaker(System.currentTimeMillis());
    }

    @VisibleForTesting
    static final clreplaced Light {

        public final int color;

        public final int onMs;

        public final int offMs;

        public Light(int color, int onMs, int offMs) {
            this.color = color;
            this.onMs = onMs;
            this.offMs = offMs;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (o == null || getClreplaced() != o.getClreplaced())
                return false;
            Light light = (Light) o;
            if (color != light.color)
                return false;
            if (onMs != light.onMs)
                return false;
            return offMs == light.offMs;
        }

        @Override
        public int hashCode() {
            int result = color;
            result = 31 * result + onMs;
            result = 31 * result + offMs;
            return result;
        }

        @Override
        public String toString() {
            return "Light{" + "color=" + color + ", onMs=" + onMs + ", offMs=" + offMs + '}';
        }
    }
}

8 Source : ShutdownThread.java
with Apache License 2.0
from lulululbj

/**
 * Makes sure we handle the shutdown gracefully.
 * Shuts off power regardless of radio state if the allotted time has preplaceded.
 */
public void run() {
    TimingsTraceLog shutdownTimingLog = newTimingsLog();
    shutdownTimingLog.traceBegin("SystemServerShutdown");
    metricShutdownStart();
    metricStarted(METRIC_SYSTEM_SERVER);
    BroadcastReceiver br = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            // We don't allow apps to cancel this, so ignore the result.
            actionDone();
        }
    };
    /*
         * Write a system property in case the system_server reboots before we
         * get to the actual hardware restart. If that happens, we'll retry at
         * the beginning of the SystemServer startup.
         */
    {
        String reason = (mReboot ? "1" : "0") + (mReason != null ? mReason : "");
        SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
    }
    /*
         * If we are rebooting into safe mode, write a system property
         * indicating so.
         */
    if (mRebootSafeMode) {
        SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
    }
    metricStarted(METRIC_SEND_BROADCAST);
    shutdownTimingLog.traceBegin("SendShutdownBroadcast");
    Log.i(TAG, "Sending shutdown broadcast...");
    // First send the high-level shut down broadcast.
    mActionDone = false;
    Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, null, br, mHandler, 0, null, null);
    final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
    synchronized (mActionDoneSync) {
        while (!mActionDone) {
            long delay = endTime - SystemClock.elapsedRealtime();
            if (delay <= 0) {
                Log.w(TAG, "Shutdown broadcast timed out");
                break;
            } else if (mRebootHasProgressBar) {
                int status = (int) ((MAX_BROADCAST_TIME - delay) * 1.0 * BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME);
                sInstance.setRebootProgress(status, null);
            }
            try {
                mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
            } catch (InterruptedException e) {
            }
        }
    }
    if (mRebootHasProgressBar) {
        sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);
    }
    // SendShutdownBroadcast
    shutdownTimingLog.traceEnd();
    metricEnded(METRIC_SEND_BROADCAST);
    Log.i(TAG, "Shutting down activity manager...");
    shutdownTimingLog.traceBegin("ShutdownActivityManager");
    metricStarted(METRIC_AM);
    final IActivityManager am = IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));
    if (am != null) {
        try {
            am.shutdown(MAX_BROADCAST_TIME);
        } catch (RemoteException e) {
        }
    }
    if (mRebootHasProgressBar) {
        sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);
    }
    // ShutdownActivityManager
    shutdownTimingLog.traceEnd();
    metricEnded(METRIC_AM);
    Log.i(TAG, "Shutting down package manager...");
    shutdownTimingLog.traceBegin("ShutdownPackageManager");
    metricStarted(METRIC_PM);
    final PackageManagerService pm = (PackageManagerService) ServiceManager.getService("package");
    if (pm != null) {
        pm.shutdown();
    }
    if (mRebootHasProgressBar) {
        sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
    }
    // ShutdownPackageManager
    shutdownTimingLog.traceEnd();
    metricEnded(METRIC_PM);
    // Shutdown radios.
    shutdownTimingLog.traceBegin("ShutdownRadios");
    metricStarted(METRIC_RADIOS);
    shutdownRadios(MAX_RADIO_WAIT_TIME);
    if (mRebootHasProgressBar) {
        sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
    }
    // ShutdownRadios
    shutdownTimingLog.traceEnd();
    metricEnded(METRIC_RADIOS);
    if (mRebootHasProgressBar) {
        sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);
        // If it's to reboot to install an update and uncrypt hasn't been
        // done yet, trigger it now.
        uncrypt();
    }
    // SystemServerShutdown
    shutdownTimingLog.traceEnd();
    metricEnded(METRIC_SYSTEM_SERVER);
    saveMetrics(mReboot, mReason);
    // Remaining work will be done by init, including vold shutdown
    rebootOrShutdown(mContext, mReboot, mReason);
}