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
19
Source : ActivityManagerCompat.java
with GNU General Public License v3.0
from MuntashirAkon
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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);
}