Merge changes I2867a158,I98de12b5
* changes: Allow shell uid without checking the package name. Allow apps receiving MediaSession callbacks to start FGS from BG.
This commit is contained in:
@@ -61,8 +61,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the system implementation of a Session. Apps will interact with the
|
* This is the system implementation of a Session. Apps will interact with the
|
||||||
@@ -1159,6 +1159,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
public void sendCommand(String packageName, int pid, int uid, String command, Bundle args,
|
public void sendCommand(String packageName, int pid, int uid, String command, Bundle args,
|
||||||
ResultReceiver cb) {
|
ResultReceiver cb) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":" + command;
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onCommand(packageName, pid, uid, command, args, cb);
|
mCb.onCommand(packageName, pid, uid, command, args, cb);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in sendCommand.", e);
|
Log.e(TAG, "Remote failure in sendCommand.", e);
|
||||||
@@ -1168,6 +1171,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
public void sendCustomAction(String packageName, int pid, int uid, String action,
|
public void sendCustomAction(String packageName, int pid, int uid, String action,
|
||||||
Bundle args) {
|
Bundle args) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":custom-" + action;
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onCustomAction(packageName, pid, uid, action, args);
|
mCb.onCustomAction(packageName, pid, uid, action, args);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in sendCustomAction.", e);
|
Log.e(TAG, "Remote failure in sendCustomAction.", e);
|
||||||
@@ -1176,6 +1182,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
|
|
||||||
public void prepare(String packageName, int pid, int uid) {
|
public void prepare(String packageName, int pid, int uid) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":prepare";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onPrepare(packageName, pid, uid);
|
mCb.onPrepare(packageName, pid, uid);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in prepare.", e);
|
Log.e(TAG, "Remote failure in prepare.", e);
|
||||||
@@ -1185,6 +1194,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
public void prepareFromMediaId(String packageName, int pid, int uid, String mediaId,
|
public void prepareFromMediaId(String packageName, int pid, int uid, String mediaId,
|
||||||
Bundle extras) {
|
Bundle extras) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":prepareFromMediaId";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onPrepareFromMediaId(packageName, pid, uid, mediaId, extras);
|
mCb.onPrepareFromMediaId(packageName, pid, uid, mediaId, extras);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in prepareFromMediaId.", e);
|
Log.e(TAG, "Remote failure in prepareFromMediaId.", e);
|
||||||
@@ -1194,6 +1206,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
public void prepareFromSearch(String packageName, int pid, int uid, String query,
|
public void prepareFromSearch(String packageName, int pid, int uid, String query,
|
||||||
Bundle extras) {
|
Bundle extras) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":prepareFromSearch";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onPrepareFromSearch(packageName, pid, uid, query, extras);
|
mCb.onPrepareFromSearch(packageName, pid, uid, query, extras);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in prepareFromSearch.", e);
|
Log.e(TAG, "Remote failure in prepareFromSearch.", e);
|
||||||
@@ -1202,6 +1217,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
|
|
||||||
public void prepareFromUri(String packageName, int pid, int uid, Uri uri, Bundle extras) {
|
public void prepareFromUri(String packageName, int pid, int uid, Uri uri, Bundle extras) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":prepareFromUri";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onPrepareFromUri(packageName, pid, uid, uri, extras);
|
mCb.onPrepareFromUri(packageName, pid, uid, uri, extras);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in prepareFromUri.", e);
|
Log.e(TAG, "Remote failure in prepareFromUri.", e);
|
||||||
@@ -1210,6 +1228,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
|
|
||||||
public void play(String packageName, int pid, int uid) {
|
public void play(String packageName, int pid, int uid) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":play";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onPlay(packageName, pid, uid);
|
mCb.onPlay(packageName, pid, uid);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in play.", e);
|
Log.e(TAG, "Remote failure in play.", e);
|
||||||
@@ -1219,6 +1240,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
public void playFromMediaId(String packageName, int pid, int uid, String mediaId,
|
public void playFromMediaId(String packageName, int pid, int uid, String mediaId,
|
||||||
Bundle extras) {
|
Bundle extras) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":playFromMediaId";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onPlayFromMediaId(packageName, pid, uid, mediaId, extras);
|
mCb.onPlayFromMediaId(packageName, pid, uid, mediaId, extras);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in playFromMediaId.", e);
|
Log.e(TAG, "Remote failure in playFromMediaId.", e);
|
||||||
@@ -1228,6 +1252,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
public void playFromSearch(String packageName, int pid, int uid, String query,
|
public void playFromSearch(String packageName, int pid, int uid, String query,
|
||||||
Bundle extras) {
|
Bundle extras) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":playFromSearch";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onPlayFromSearch(packageName, pid, uid, query, extras);
|
mCb.onPlayFromSearch(packageName, pid, uid, query, extras);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in playFromSearch.", e);
|
Log.e(TAG, "Remote failure in playFromSearch.", e);
|
||||||
@@ -1236,6 +1263,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
|
|
||||||
public void playFromUri(String packageName, int pid, int uid, Uri uri, Bundle extras) {
|
public void playFromUri(String packageName, int pid, int uid, Uri uri, Bundle extras) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":playFromUri";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onPlayFromUri(packageName, pid, uid, uri, extras);
|
mCb.onPlayFromUri(packageName, pid, uid, uri, extras);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in playFromUri.", e);
|
Log.e(TAG, "Remote failure in playFromUri.", e);
|
||||||
@@ -1244,6 +1274,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
|
|
||||||
public void skipToTrack(String packageName, int pid, int uid, long id) {
|
public void skipToTrack(String packageName, int pid, int uid, long id) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":skipToTrack";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onSkipToTrack(packageName, pid, uid, id);
|
mCb.onSkipToTrack(packageName, pid, uid, id);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in skipToTrack", e);
|
Log.e(TAG, "Remote failure in skipToTrack", e);
|
||||||
@@ -1252,6 +1285,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
|
|
||||||
public void pause(String packageName, int pid, int uid) {
|
public void pause(String packageName, int pid, int uid) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":pause";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onPause(packageName, pid, uid);
|
mCb.onPause(packageName, pid, uid);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in pause.", e);
|
Log.e(TAG, "Remote failure in pause.", e);
|
||||||
@@ -1260,6 +1296,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
|
|
||||||
public void stop(String packageName, int pid, int uid) {
|
public void stop(String packageName, int pid, int uid) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":stop";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onStop(packageName, pid, uid);
|
mCb.onStop(packageName, pid, uid);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in stop.", e);
|
Log.e(TAG, "Remote failure in stop.", e);
|
||||||
@@ -1268,6 +1307,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
|
|
||||||
public void next(String packageName, int pid, int uid) {
|
public void next(String packageName, int pid, int uid) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":next";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onNext(packageName, pid, uid);
|
mCb.onNext(packageName, pid, uid);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in next.", e);
|
Log.e(TAG, "Remote failure in next.", e);
|
||||||
@@ -1276,6 +1318,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
|
|
||||||
public void previous(String packageName, int pid, int uid) {
|
public void previous(String packageName, int pid, int uid) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":previous";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onPrevious(packageName, pid, uid);
|
mCb.onPrevious(packageName, pid, uid);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in previous.", e);
|
Log.e(TAG, "Remote failure in previous.", e);
|
||||||
@@ -1284,6 +1329,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
|
|
||||||
public void fastForward(String packageName, int pid, int uid) {
|
public void fastForward(String packageName, int pid, int uid) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":fastForward";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onFastForward(packageName, pid, uid);
|
mCb.onFastForward(packageName, pid, uid);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in fastForward.", e);
|
Log.e(TAG, "Remote failure in fastForward.", e);
|
||||||
@@ -1292,6 +1340,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
|
|
||||||
public void rewind(String packageName, int pid, int uid) {
|
public void rewind(String packageName, int pid, int uid) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":rewind";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onRewind(packageName, pid, uid);
|
mCb.onRewind(packageName, pid, uid);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in rewind.", e);
|
Log.e(TAG, "Remote failure in rewind.", e);
|
||||||
@@ -1300,6 +1351,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
|
|
||||||
public void seekTo(String packageName, int pid, int uid, long pos) {
|
public void seekTo(String packageName, int pid, int uid, long pos) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":seekTo";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onSeekTo(packageName, pid, uid, pos);
|
mCb.onSeekTo(packageName, pid, uid, pos);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in seekTo.", e);
|
Log.e(TAG, "Remote failure in seekTo.", e);
|
||||||
@@ -1308,6 +1362,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
|
|
||||||
public void rate(String packageName, int pid, int uid, Rating rating) {
|
public void rate(String packageName, int pid, int uid, Rating rating) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":rate";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onRate(packageName, pid, uid, rating);
|
mCb.onRate(packageName, pid, uid, rating);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in rate.", e);
|
Log.e(TAG, "Remote failure in rate.", e);
|
||||||
@@ -1316,6 +1373,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
|
|
||||||
public void setPlaybackSpeed(String packageName, int pid, int uid, float speed) {
|
public void setPlaybackSpeed(String packageName, int pid, int uid, float speed) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":setPlaybackSpeed";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onSetPlaybackSpeed(packageName, pid, uid, speed);
|
mCb.onSetPlaybackSpeed(packageName, pid, uid, speed);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in setPlaybackSpeed.", e);
|
Log.e(TAG, "Remote failure in setPlaybackSpeed.", e);
|
||||||
@@ -1325,6 +1385,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
public void adjustVolume(String packageName, int pid, int uid, boolean asSystemService,
|
public void adjustVolume(String packageName, int pid, int uid, boolean asSystemService,
|
||||||
int direction) {
|
int direction) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":adjustVolume";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
if (asSystemService) {
|
if (asSystemService) {
|
||||||
mCb.onAdjustVolume(mContext.getPackageName(), Process.myPid(),
|
mCb.onAdjustVolume(mContext.getPackageName(), Process.myPid(),
|
||||||
Process.SYSTEM_UID, direction);
|
Process.SYSTEM_UID, direction);
|
||||||
@@ -1338,6 +1401,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
|
|||||||
|
|
||||||
public void setVolumeTo(String packageName, int pid, int uid, int value) {
|
public void setVolumeTo(String packageName, int pid, int uid, int value) {
|
||||||
try {
|
try {
|
||||||
|
final String reason = TAG + ":setVolumeTo";
|
||||||
|
mService.tempAllowlistTargetPkgIfPossible(getUid(), getPackageName(),
|
||||||
|
pid, uid, packageName, reason);
|
||||||
mCb.onSetVolumeTo(packageName, pid, uid, value);
|
mCb.onSetVolumeTo(packageName, pid, uid, value);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.e(TAG, "Remote failure in setVolumeTo.", e);
|
Log.e(TAG, "Remote failure in setVolumeTo.", e);
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.PackageManagerInternal;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.media.AudioPlaybackConfiguration;
|
import android.media.AudioPlaybackConfiguration;
|
||||||
import android.media.AudioSystem;
|
import android.media.AudioSystem;
|
||||||
@@ -85,6 +86,7 @@ import android.view.ViewConfiguration;
|
|||||||
import com.android.internal.R;
|
import com.android.internal.R;
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import com.android.server.LocalManagerRegistry;
|
import com.android.server.LocalManagerRegistry;
|
||||||
|
import com.android.server.LocalServices;
|
||||||
import com.android.server.SystemService;
|
import com.android.server.SystemService;
|
||||||
import com.android.server.Watchdog;
|
import com.android.server.Watchdog;
|
||||||
import com.android.server.Watchdog.Monitor;
|
import com.android.server.Watchdog.Monitor;
|
||||||
@@ -538,14 +540,19 @@ public class MediaSessionService extends SystemService implements Monitor {
|
|||||||
if (TextUtils.isEmpty(packageName)) {
|
if (TextUtils.isEmpty(packageName)) {
|
||||||
throw new IllegalArgumentException("packageName may not be empty");
|
throw new IllegalArgumentException("packageName may not be empty");
|
||||||
}
|
}
|
||||||
String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
|
if (uid == Process.ROOT_UID || uid == Process.SHELL_UID) {
|
||||||
final int packageCount = packages.length;
|
// If the caller is shell, then trust the packageName given and allow it
|
||||||
for (int i = 0; i < packageCount; i++) {
|
// to proceed.
|
||||||
if (packageName.equals(packages[i])) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
final PackageManagerInternal packageManagerInternal =
|
||||||
|
LocalServices.getService(PackageManagerInternal.class);
|
||||||
|
final int actualUid = packageManagerInternal.getPackageUid(
|
||||||
|
packageName, 0 /* flags */, UserHandle.getUserId(uid));
|
||||||
|
if (!UserHandle.isSameApp(uid, actualUid)) {
|
||||||
|
throw new IllegalArgumentException("packageName does not belong to the calling uid; "
|
||||||
|
+ "pkg=" + packageName + ", uid=" + uid);
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("packageName is not owned by the calling process");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tempAllowlistTargetPkgIfPossible(int targetUid, String targetPackage,
|
void tempAllowlistTargetPkgIfPossible(int targetUid, String targetPackage,
|
||||||
|
|||||||
Reference in New Issue
Block a user