Подтвердить что ты не робот

Как получить имя пакета приложения или UID, который пытается связать мой сервис с функцией onBind?

У меня есть служба в приложении, и я могу связаться с этой службой из разных приложений. И когда приложения пытаются связать эту службу, я хочу знать, какое приложение пытается связать мой сервис с функцией onBind, но я не могу получить имя пакета или UID этого приложения в функции onBind.

Можно ли получить имя приложения или UID, который пытается связать мой сервис с функцией onBind?

4b9b3361

Ответ 1

Для определения вызывающего приложения вы можете использовать следующее.

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

Важно отметить JavaDoc для getCallingUid(), в котором говорится:

Верните Linux uid, назначенный процессу, который отправил вам текущую транзакцию, которая обрабатывается. Этот uid можно использовать с системными службами более высокого уровня, чтобы определить его личность и проверить разрешения. Если текущий поток в настоящий момент не выполняет входящую транзакцию, возвращается его собственный uid.

Ответ 2

Вы не можете этого сделать.

onBind() вызывается из Android "менеджер жизненного цикла" (составляя полезное имя) и будет вызываться только один раз для каждого намерения (чтобы он мог узнать, какой Binder должен быть возвращен для этого намерения).

Затем вызовы вашей службы переходят через этот Binder, и вы можете сделать Binder.getCallingUid() в любом из этих методов.

Ответ 3

Вышеприведенный ответ не сработал у меня. Но небольшая модификация сделала трюк. Это хорошо работает с 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();
    }
}

Из приведенного выше ответа вам нужно изменить только от Binder.getCallingUid() до msg.sendingUid

Ответ 4

Принятый ответ был не совсем прав! Почему? Если два или более приложения используют один и тот же 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.

Ответ 5

Я смотрел, как 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, они должны быть подписаны одним и тем же ключом, поэтому им можно доверять одинаково.