android: validate the identity of intent sender

孤街浪徒 提交于 2019-12-04 04:07:15

Sorry for late response...

Bind takes time, and more importantly, its asynchronous. However, there is a way to make a synchronous bind - assuming of course the service you attempt to contact is already started at the time. Android allowed for this more for BroadcastReceivers (which are async in nature, and thus can't use normal bindService) a BroadcastReceiver has a "peekService" method.

If you want to use it without listening to a broadcast, you can by doing:

final IBinder[] b = new IBinder[1];
new BroadcastReceiver() { 
    public void onReceive(Context context, Intent intent) {
        b[0] = peekService(context, intent);
    }
}.onReceiver(context, intent);

IMyInterface i = IMyInterface.Stub.asInterface(b[0);

note that you don't bind to the service, so make sure to peek at on each use.

As always with a challenging question here i never get a proper, if ANY!' answer, so i'm forced to find it myself.

The problem with Intents is that it's not possible to get the sender as they are the parallel to mulicast in a network where there sender's address is not important.

If i wish to get the snder's UID i need to make a "remote" process even if he is local, instead of using broadcast IPC i need to use AIDL with IBInder implementation. Once i have a Binder object i can call in my service getCallingUid() and get the uid of the caller, this will allow me to ask PackageManager to give me it's public certificate (without asking the process itself, i ask the OS) and compare it to a set of certificates i prepared in advance in the apk.

The calling application on the other side(the other process that sends me it's ID) just has to use the bindService(service, conn, flags) method to bind to me. The disadvantage to this approach is ofcourse the time consuming process, Bind takes time, it's an async call that pass through the kernel and is not as fast as binding to a local service. Moreover since i might have several applications i need to synchronize the access my internal ID so only the first binding call that didn't fail will set and ID for me. I still need to check if i can use the Messanger method that prevents the multi thread issues.

Hopes this helps someone else.

Rupert Rawnsley

As already stated, binding is probably the best solution to this. However, you could consider switching to an Activity rather than a BroadcastReceiver then you can use getCallingActivity(), assuming you launched with startActivityForResult().

Declare you Activity as follows to make it "silent" like a BroadcastReceiver:

<activity
    android:name=".FauxReceiver"
    android:theme="@android:style/Theme.NoDisplay" 
    android:excludeFromRecents="true"
    android:noHistory="true"
>
    <intent-filter>
        ...
    </intent-filter>
</activity>

Inspiration: How to get the sender of an Intent?

I was looking for a way to verify the package name of the application that sent the intent received by my intent-filter. That activity in my app that handles the intent-filter requires that the intent sender includes their process id in an Intent Extras field. My receiving activity can then get the associated application package name from the ActivityManager.

Here is some example code I found while shifting through StackOverflow.

Constants needed for both Apps

public static final String EXTRA_APP_ID;
public static final String ACTION_VERIFY = "com.example.receivingapp.action.VERIFY";

Calling Activity

    Intent verifyIntent = new Intent();
    verifyIntent.setAction(Consts.ACTION_VERIFY);
    verifyIntent.putExtra(EXTRA_APP_ID, android.os.Process.myPid());
    // Verify that the intent will resolve to an activity
    if (verifyIntent.resolveActivity(getPackageManager()) != null) {
    startActivityForResult(verifyIntent, Consts.REQUEST_VERIFY);
    } else {
       Log.d(TAG, "Application not found.");
    }

Receiving App

Manifest

        <activity
            android:name="com.example.receivingapp.ReceivingActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="com.example.receivingapp.VERIFY" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

ReceivingActivity

if (getIntent().hasExtra(OnyxCoreConsts.EXTRA_APP_ID)) {
    string appName = null;  
    // Resolve intent
    if (getIntent().getAction().equals(ACTION_VERIFY) {    
         int appPid = getIntent().getIntExtra(EXTRA_APP_ID, -1);
         if (-1 != mAppPid) {
             appName = Utils.getAppNameByPID(mContext, mAppPid);
         }
         if (null != appName && !"".equalsIgnoreCase(appName)) {
              // Do something with the application package name
         }
    }
}

Utils class

public static String getAppNameByPID(Context context, int pid){
        ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

        for (RunningAppProcessInfo processInfo : manager.getRunningAppProcesses()) {
            if (processInfo.pid == pid) {
                return processInfo.processName;
            }
        }
        return "";
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!