21

我在一个应用程序中有一个服务,我可以从不同的应用程序访问这个服务。当应用程序尝试绑定此服务时,我想知道哪个应用程序试图在 onBind 函数中绑定我的服务,但我无法在 onBind 函数中获取此应用程序的包名称或 UID。

是否可以获得试图在 onBind 函数中绑定我的服务的应用程序名称或 UID?

4

6 回答 6

25

您可以使用以下内容来确定调用应用程序。

 String callingApp = context.getPackageManager().getNameForUid(Binder.getCallingUid());

重要的是要注意JavaDocgetCallingUid()说:

返回分配给向您发送当前正在处理的事务的进程的 Linux uid。此 uid 可与更高级别的系统服务一起使用,以确定其身份并检查权限。如果当前线程当前没有执行传入事务,则返回它自己的 uid。

于 2012-10-16T16:07:00.880 回答
5

你不能这样做。

onBind() 从 Android“生命周期管理器”(组成一个有用的名称)调用,并且只会为每个 Intent 调用一次(因此它可以了解应该为该 Intent 返回哪个 Binder)。

然后对您的服务的调用通过该 Binder 进行,您可以在其中任何一种方法中执行 Binder.getCallingUid()。

于 2013-02-28T18:28:03.187 回答
5

接受的答案不太正确!为什么?如果两个或多个应用程序使用相同android:sharedUserId的,该方法Binder.getCallingUid()将返回相同的uid并将getPackageManager().getNameForUid(uid)返回相同的字符串,它看起来像:com.codezjx.demo:10058,但不是包名!

正确的方法是使用pid

int pid = Binder.getCallingPid();

然后使用pid获取包名ActivityManager,每个进程可以持有多个包,如下图:

private String[] getPackageNames(Context context, int pid) {
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningAppProcessInfo> infos = am.getRunningAppProcesses();
    if (infos != null && infos.size() > 0) {
        for(RunningAppProcessInfo info : infos) {
            if(info.pid == pid) {
                return info.pkgList;
            }
        }
    }
    return null;
}

警告:使用方法时Binder.getCallingPid(),如果当前线程当前未执行传入事务,则返回其自己的 pid。这意味着您需要在 AIDL 公开的接口方法中调用此方法。

于 2016-08-03T07:22:02.130 回答
5

上述接受的答案对我不起作用。但一个小小的修改就奏效了。这非常适合基于Messenger的通信。

public class BoundService extends Service {

    public static final int TEST = 100;
    private final Messenger messenger = new Messenger(new MessageHandler());

    class MessageHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {

            String callerId = getApplicationContext().getPackageManager().getNameForUid(msg.sendingUid);
            Toast.makeText(getApplicationContext(), "Calling App: " + callerId, Toast.LENGTH_SHORT).show();

            switch (msg.what) {
                case TEST:
                    Log.e("BoundService", "Test message successfully received.")
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return messenger.getBinder();
    }
}

从上面的答案,你只需要将 fromBinder.getCallingUid()改为msg.sendingUid

于 2018-02-02T00:08:36.503 回答
2

我正在寻找如何LocationManagerService限制访问,这是我发现的:

  1. 每当您尝试访问位置时,它们都会让您传递包名称
// android.location.ILocationService

Location getLastLocation(LocationRequest request, String packageName) throws RemoteException;
  1. 在处理事务时,他们检查调用者 uid 是否与提供的包名称匹配(如其他答案中所述,可能有多个包名称共享相同的 uid)。
// com.android.server.LocationManagerService

public Location getLastLocation(LocationRequest r, String packageName) {
    ...
    checkPackageName(packageName);

    // From this point on we assume that the provided packageName is the real one
    if (mBlacklist.isBlacklisted(packageName)) {
        if (D) {
            Log.d(TAG, "not returning last loc for blacklisted app: "
                    + packageName);
        }
        return null;
    }
    ...
}
...
private void checkPackageName(String packageName) {
    if (packageName == null) {
        throw new SecurityException("invalid package name: " + null);
    }
    int uid = Binder.getCallingUid();
    String[] packages = mPackageManager.getPackagesForUid(uid);
    if (packages == null) {
        throw new SecurityException("invalid UID " + uid);
    }
    for (String pkg : packages) {
        if (packageName.equals(pkg)) return;
    }
    throw new SecurityException("invalid package name: " + packageName);
}

我想,这是令人满意的,因为要让应用程序共享 uid,它们需要使用相同的密钥进行签名,因此可以同样受到信任

于 2019-08-07T05:16:34.723 回答
0

您现在可以使用getPackagesForUid而不是getNameForUid.

getNamepostPends uid,getPackages没有)

class MyService : Service() {


    override fun onBind(intent: Intent): IBinder {
        return Messenger(IncomingHandler(this, packageManager).binder
    }

    internal class IncomingHandler(
        private val context: Context,
        private val packageManager: PackageManager
    ) : Handler() {

         override fun handleMessage(msg: Message) {
            val sendingUid = msg.sendingUid
            val potentialCallingPackageNames = packageManager.getPackagesForUid(sendingUid)!!.toList()
            Log.d("TUT", "One of these packages called you $potentialCallingPackageNames")
         }
    }
}

请记住,如果您希望系统应用程序调用您,那么它的 UID 将匹配许多其他系统应用程序,因此列表将有很多项目。如果它只是另一个应用程序呼叫您,那么列表可能会有 1 个项目。

于 2020-07-03T13:58:45.777 回答