سؤال

The projcet involves modifying Android to block/deny launching of particular apps. So if user tries to launch any of the pre-listed apps by any means, that app shouldn't get launched.

I'll be modifying Android source code. What are the different ways to do it? Suggestions are welcome.

I think one of the possible ways to do that is to modify Process.java in frameworks/base/core/java/android/os. This class has start function which receives uid as an input paramenter. I think from this parameter we can get to know that for which app new process is being created. Is this the correct way to do it?

Also, as the apps are launched using intents, is it possible (by modifying any class) to remove particular intents?

هل كانت مفيدة؟

المحلول

In general, when an intent can be handled by an application(its activity, service), and the user prefers that application to handle it. The ActivityManagerService(Ams) in Android framework will first see whether the corresponding application of the target activity/service is still alive. If it hasn't been started yet or killed, the Ams will start that application by calling startProcessLocked method.

final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting,
            boolean isolated) {
    //you can get the uid from ApplicationInfo.uid
    ...
    startProcessLocked(app, hostingType, hostingNameStr);
    ...
}

private final void startProcessLocked(ProcessRecord app,
            String hostingType, String hostingNameStr) {
    //prepare its uid, gid, gids for starting that process
    ...
    Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, null, null);
    ...
}

So in that method, it start a new process. The Process.start is what you have mentioned in your question, and it finally calls Zygote to fork a new process.

I think intercepting the application startup process in Ams is a better way. You can get more information about this application and it is also the upstream of your Process.start method.

UPDATE:

Just noticed that you were thinking about restricting intent. An intent can be handled by multiple applications, so we cannot restrict applications from sending a particular intent. But we can modify the resolving process. Resolving means the Android framework need to determine which activity/service can handle this intent. If there are multiple choices and the user haven't set any preference, then the following dialog will appear:

Intent Handling

So it is possible to modify the resolving process to let the Android framework discard the fact that your specific application is able to handle that intent. I think this is also a way to do your work but it is much more compilicated because Android resolves intent differently for activity, service and receiver. For activity, Ams will call resolveIntent in PackageManagerService to get which activity to start. For service, it is the resolveService method in PackageManagerService get called. So you need to handle them differently. But since they will all get a list of ResolveInfo in their implementation, you can just filter out your application easily. For example, in resolveIntent in PackageManagerService:

@Override
public ResolveInfo resolveIntent(Intent intent, String resolvedType,
        int flags, int userId) {
    if (!sUserManager.exists(userId)) return null;
    enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "resolve intent");
    List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
    //filter out here!!!!
    return chooseBestActivity(intent, resolvedType, flags, query, userId);
}

You can easily get the ApplicationInfo from the ResolveInfo if you take a look at ResolveInfo.java.

For receiver, it is even more complicated because receivers registered in AndroidManifest.xml and by registerReceiver(...) are different. If the intent in broadcastIntent hasn't set the flag FLAG_RECEIVER_REGISTERED_ONLY(common case), then the resolving result would be a list of receivers that listen to that broadcast, which may contain two kinds of receivers. For those in AndroidManifest.xml, Ams will call queryIntentReceiver in PackageManagerService to get a list of receivers that listen to a broadcast. For those registered dynamically by registerReciever(...), they are managed by ActivityManagerService not PackageManagerService, so Ams will directly call mReceiverResolver.queryIntent to get those receivers. The mReceiverResolver is defined as:

final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
        = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
        ...
}

So what you need to do is override the queryIntent method to filter out the receivers in your application. For ContentProvider, the method is resolveContentProvider in PackageManagerService. Same way to handle it.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top