Как получить имя пакета приложения или UID, который пытается связать мой сервис с функцией onBind?
У меня есть служба в приложении, и я могу связаться с этой службой из разных приложений.
И когда приложения пытаются связать эту службу, я хочу знать, какое приложение пытается связать мой сервис с функцией onBind,
но я не могу получить имя пакета или UID этого приложения в функции onBind.
Можно ли получить имя приложения или UID, который пытается связать мой сервис с функцией onBind?
Ответы
Ответ 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
ограничивает доступ, и вот что я нашел:
- Они заставляют вас передавать имя пакета всякий раз, когда вы пытаетесь получить доступ к местоположению
// android.location.ILocationService
Location getLastLocation(LocationRequest request, String packageName) throws RemoteException;
- При обработке транзакции они проверяют, совпадает ли 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, они должны быть подписаны одним и тем же ключом, поэтому им можно доверять одинаково.