Merge "Add UsbDebuggingManager and UsbDebuggingActivity" into jb-mr1-dev
This commit is contained in:
@@ -87,4 +87,12 @@ interface IUsbManager
|
||||
|
||||
/* Sets the file path for USB mass storage backing file. */
|
||||
void setMassStorageBackingFile(String path);
|
||||
|
||||
/* Allow USB debugging from the attached host. If alwaysAllow is true, add the
|
||||
* the public key to list of host keys that the user has approved.
|
||||
*/
|
||||
void allowUsbDebugging(boolean alwaysAllow, String publicKey);
|
||||
|
||||
/* Deny USB debugging from the attached host */
|
||||
void denyUsbDebugging();
|
||||
}
|
||||
|
||||
@@ -132,6 +132,14 @@
|
||||
android:excludeFromRecents="true">
|
||||
</activity>
|
||||
|
||||
<!-- started from UsbDebuggingManager -->
|
||||
<activity android:name=".usb.UsbDebuggingActivity"
|
||||
android:permission="android.permission.MANAGE_USB"
|
||||
android:theme="@*android:style/Theme.Holo.Dialog.Alert"
|
||||
android:finishOnCloseSystemDialogs="true"
|
||||
android:excludeFromRecents="true">
|
||||
</activity>
|
||||
|
||||
<!-- started from NetworkPolicyManagerService -->
|
||||
<activity
|
||||
android:name=".net.NetworkOverLimitActivity"
|
||||
|
||||
@@ -154,6 +154,15 @@
|
||||
<!-- Checkbox label for USB accessory dialogs. [CHAR LIMIT=50] -->
|
||||
<string name="always_use_accessory">Use by default for this USB accessory</string>
|
||||
|
||||
<!-- Title of confirmation dialog for USB debugging -->
|
||||
<string name="usb_debugging_title">Allow USB Debugging?</string>
|
||||
|
||||
<!-- Message of confirmation dialog for USB debugging -->
|
||||
<string name="usb_debugging_message">Allow USB Debugging from this computer?\nYour RSA key fingerprint is\n<xliff:g id="fingerprint">%1$s</xliff:g></string>
|
||||
|
||||
<!-- Option to always allow USB debugging from the attached computer -->
|
||||
<string name="usb_debugging_always">Always allow this computer</string>
|
||||
|
||||
<!-- Checkbox label for application compatibility mode ON (zooming app to look like it's running
|
||||
on a phone). [CHAR LIMIT=25] -->
|
||||
<string name="compat_mode_on">Zoom to fill screen</string>
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.usb;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.Typeface;
|
||||
import android.hardware.usb.IUsbManager;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.ServiceManager;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.app.AlertActivity;
|
||||
import com.android.internal.app.AlertController;
|
||||
|
||||
import com.android.systemui.R;
|
||||
|
||||
public class UsbDebuggingActivity extends AlertActivity
|
||||
implements DialogInterface.OnClickListener {
|
||||
private static final String TAG = "UsbDebuggingActivity";
|
||||
|
||||
private CheckBox mAlwaysAllow;
|
||||
private UsbDisconnectedReceiver mDisconnectedReceiver;
|
||||
private String mKey;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
mDisconnectedReceiver = new UsbDisconnectedReceiver(this);
|
||||
Intent intent = getIntent();
|
||||
String fingerprints = intent.getStringExtra("fingerprints");
|
||||
mKey = intent.getStringExtra("key");
|
||||
|
||||
if (fingerprints == null || mKey == null) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
final AlertController.AlertParams ap = mAlertParams;
|
||||
ap.mTitle = getString(R.string.usb_debugging_title);
|
||||
ap.mIconId = com.android.internal.R.drawable.ic_dialog_usb;
|
||||
ap.mMessage = getString(R.string.usb_debugging_message, fingerprints);
|
||||
ap.mPositiveButtonText = getString(android.R.string.ok);
|
||||
ap.mNegativeButtonText = getString(android.R.string.cancel);
|
||||
ap.mPositiveButtonListener = this;
|
||||
ap.mNegativeButtonListener = this;
|
||||
|
||||
// add "always allow" checkbox
|
||||
LayoutInflater inflater = LayoutInflater.from(ap.mContext);
|
||||
View checkbox = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
|
||||
mAlwaysAllow = (CheckBox)checkbox.findViewById(com.android.internal.R.id.alwaysUse);
|
||||
mAlwaysAllow.setText(getString(R.string.usb_debugging_always));
|
||||
ap.mView = checkbox;
|
||||
|
||||
setupAlert();
|
||||
}
|
||||
|
||||
private class UsbDisconnectedReceiver extends BroadcastReceiver {
|
||||
private final Activity mActivity;
|
||||
public UsbDisconnectedReceiver(Activity activity) {
|
||||
mActivity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context content, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (!UsbManager.ACTION_USB_STATE.equals(action)) {
|
||||
return;
|
||||
}
|
||||
boolean connected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
|
||||
if (!connected) {
|
||||
mActivity.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_STATE);
|
||||
registerReceiver(mDisconnectedReceiver, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
if (mDisconnectedReceiver != null) {
|
||||
unregisterReceiver(mDisconnectedReceiver);
|
||||
}
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
boolean allow = (which == AlertDialog.BUTTON_POSITIVE);
|
||||
boolean alwaysAllow = allow && mAlwaysAllow.isChecked();
|
||||
try {
|
||||
IBinder b = ServiceManager.getService(USB_SERVICE);
|
||||
IUsbManager service = IUsbManager.Stub.asInterface(b);
|
||||
if (allow) {
|
||||
service.allowUsbDebugging(alwaysAllow, mKey);
|
||||
} else {
|
||||
service.denyUsbDebugging();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Unable to notify Usb service", e);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
||||
322
services/java/com/android/server/usb/UsbDebuggingManager.java
Normal file
322
services/java/com/android/server/usb/UsbDebuggingManager.java
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions an
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.usb;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.LocalSocket;
|
||||
import android.net.LocalSocketAddress;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Environment;
|
||||
import android.os.FileUtils;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Process;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Slog;
|
||||
import android.util.Base64;
|
||||
|
||||
import java.lang.Thread;
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class UsbDebuggingManager implements Runnable {
|
||||
private static final String TAG = "UsbDebuggingManager";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final String ADBD_SOCKET = "adbd";
|
||||
private final String ADB_DIRECTORY = "misc/adb";
|
||||
private final String ADB_KEYS_FILE = "adb_keys";
|
||||
private final int BUFFER_SIZE = 4096;
|
||||
|
||||
private final Context mContext;
|
||||
private final Thread mThread;
|
||||
private final Handler mHandler;
|
||||
private final HandlerThread mHandlerThread;
|
||||
private boolean mAdbEnabled = false;
|
||||
private String mFingerprints;
|
||||
private LocalSocket mSocket = null;
|
||||
private OutputStream mOutputStream = null;
|
||||
|
||||
public UsbDebuggingManager(Context context) {
|
||||
mThread = new Thread(this);
|
||||
mHandlerThread = new HandlerThread("UsbDebuggingHandler");
|
||||
mHandlerThread.start();
|
||||
mHandler = new UsbDebuggingHandler(mHandlerThread.getLooper());
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
private void listenToSocket() throws IOException {
|
||||
try {
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
LocalSocketAddress address = new LocalSocketAddress(ADBD_SOCKET,
|
||||
LocalSocketAddress.Namespace.RESERVED);
|
||||
InputStream inputStream = null;
|
||||
|
||||
mSocket = new LocalSocket();
|
||||
mSocket.connect(address);
|
||||
|
||||
mOutputStream = mSocket.getOutputStream();
|
||||
inputStream = mSocket.getInputStream();
|
||||
|
||||
while (true) {
|
||||
int count = inputStream.read(buffer);
|
||||
if (count < 0) {
|
||||
Slog.e(TAG, "got " + count + " reading");
|
||||
break;
|
||||
}
|
||||
|
||||
if (buffer[0] == 'P' && buffer[1] == 'K') {
|
||||
String key = new String(Arrays.copyOfRange(buffer, 2, count));
|
||||
Slog.d(TAG, "Received public key: " + key);
|
||||
Message msg = mHandler.obtainMessage(UsbDebuggingHandler.MESSAGE_ADB_CONFIRM);
|
||||
msg.obj = key;
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
else {
|
||||
Slog.e(TAG, "Wrong message: " + (new String(Arrays.copyOfRange(buffer, 0, 2))));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Slog.e(TAG, "Communication error: ", ex);
|
||||
throw ex;
|
||||
} finally {
|
||||
closeSocket();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (mAdbEnabled) {
|
||||
try {
|
||||
listenToSocket();
|
||||
} catch (Exception e) {
|
||||
/* Don't loop too fast if adbd dies, before init restarts it */
|
||||
SystemClock.sleep(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void closeSocket() {
|
||||
try {
|
||||
mOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
Slog.e(TAG, "Failed closing output stream: " + e);
|
||||
}
|
||||
|
||||
try {
|
||||
mSocket.close();
|
||||
} catch (IOException ex) {
|
||||
Slog.e(TAG, "Failed closing socket: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendResponse(String msg) {
|
||||
if (mOutputStream != null) {
|
||||
try {
|
||||
mOutputStream.write(msg.getBytes());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
Slog.e(TAG, "Failed to write response:", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UsbDebuggingHandler extends Handler {
|
||||
private static final int MESSAGE_ADB_ENABLED = 1;
|
||||
private static final int MESSAGE_ADB_DISABLED = 2;
|
||||
private static final int MESSAGE_ADB_ALLOW = 3;
|
||||
private static final int MESSAGE_ADB_DENY = 4;
|
||||
private static final int MESSAGE_ADB_CONFIRM = 5;
|
||||
|
||||
public UsbDebuggingHandler(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MESSAGE_ADB_ENABLED:
|
||||
if (mAdbEnabled)
|
||||
break;
|
||||
|
||||
mAdbEnabled = true;
|
||||
|
||||
mThread.start();
|
||||
|
||||
break;
|
||||
|
||||
case MESSAGE_ADB_DISABLED:
|
||||
if (!mAdbEnabled)
|
||||
break;
|
||||
|
||||
mAdbEnabled = false;
|
||||
closeSocket();
|
||||
|
||||
try {
|
||||
mThread.join();
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
|
||||
mOutputStream = null;
|
||||
mSocket = null;
|
||||
|
||||
case MESSAGE_ADB_ALLOW: {
|
||||
String key = (String)msg.obj;
|
||||
String fingerprints = getFingerprints(key);
|
||||
|
||||
if (!fingerprints.equals(mFingerprints)) {
|
||||
Slog.e(TAG, "Fingerprints do not match. Got "
|
||||
+ fingerprints + ", expected " + mFingerprints);
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg.arg1 == 1) {
|
||||
writeKey(key);
|
||||
}
|
||||
|
||||
sendResponse("OK");
|
||||
break;
|
||||
}
|
||||
|
||||
case MESSAGE_ADB_DENY:
|
||||
sendResponse("NO");
|
||||
break;
|
||||
|
||||
case MESSAGE_ADB_CONFIRM: {
|
||||
String key = (String)msg.obj;
|
||||
mFingerprints = getFingerprints(key);
|
||||
showConfirmationDialog(key, mFingerprints);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getFingerprints(String key) {
|
||||
String hex = "0123456789ABCDEF";
|
||||
StringBuilder sb = new StringBuilder();
|
||||
MessageDigest digester;
|
||||
|
||||
try {
|
||||
digester = MessageDigest.getInstance("MD5");
|
||||
} catch (Exception ex) {
|
||||
Slog.e(TAG, "Error getting digester: " + ex);
|
||||
return "";
|
||||
}
|
||||
|
||||
byte[] base64_data = key.split("\\s+")[0].getBytes();
|
||||
byte[] digest = digester.digest(Base64.decode(base64_data, Base64.DEFAULT));
|
||||
|
||||
for (int i = 0; i < digest.length; i++) {
|
||||
sb.append(hex.charAt((digest[i] >> 4) & 0xf));
|
||||
sb.append(hex.charAt(digest[i] & 0xf));
|
||||
if (i < digest.length - 1)
|
||||
sb.append(":");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void showConfirmationDialog(String key, String fingerprints) {
|
||||
Intent dialogIntent = new Intent();
|
||||
|
||||
dialogIntent.setClassName("com.android.systemui",
|
||||
"com.android.systemui.usb.UsbDebuggingActivity");
|
||||
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
dialogIntent.putExtra("key", key);
|
||||
dialogIntent.putExtra("fingerprints", fingerprints);
|
||||
try {
|
||||
mContext.startActivity(dialogIntent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Slog.e(TAG, "unable to start UsbDebuggingActivity");
|
||||
}
|
||||
}
|
||||
|
||||
private void writeKey(String key) {
|
||||
File dataDir = Environment.getDataDirectory();
|
||||
File adbDir = new File(dataDir, ADB_DIRECTORY);
|
||||
|
||||
if (!adbDir.exists()) {
|
||||
Slog.e(TAG, "ADB data directory does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
File keyFile = new File(adbDir, ADB_KEYS_FILE);
|
||||
|
||||
if (!keyFile.exists()) {
|
||||
keyFile.createNewFile();
|
||||
FileUtils.setPermissions(keyFile.toString(),
|
||||
FileUtils.S_IRUSR | FileUtils.S_IWUSR |
|
||||
FileUtils.S_IRGRP, -1, -1);
|
||||
}
|
||||
|
||||
FileOutputStream fo = new FileOutputStream(keyFile, true);
|
||||
fo.write(key.getBytes());
|
||||
fo.write('\n');
|
||||
fo.close();
|
||||
}
|
||||
catch (IOException ex) {
|
||||
Slog.e(TAG, "Error writing key:" + ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setAdbEnabled(boolean enabled) {
|
||||
mHandler.sendEmptyMessage(enabled ? UsbDebuggingHandler.MESSAGE_ADB_ENABLED
|
||||
: UsbDebuggingHandler.MESSAGE_ADB_DISABLED);
|
||||
}
|
||||
|
||||
public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
|
||||
Message msg = mHandler.obtainMessage(UsbDebuggingHandler.MESSAGE_ADB_ALLOW);
|
||||
msg.arg1 = alwaysAllow ? 1 : 0;
|
||||
msg.obj = publicKey;
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
|
||||
public void denyUsbDebugging() {
|
||||
mHandler.sendEmptyMessage(UsbDebuggingHandler.MESSAGE_ADB_DENY);
|
||||
}
|
||||
|
||||
|
||||
public void dump(FileDescriptor fd, PrintWriter pw) {
|
||||
pw.println(" USB Debugging State:");
|
||||
pw.println(" Connected to adbd: " + (mOutputStream != null));
|
||||
pw.println(" Last key received: " + mFingerprints);
|
||||
pw.println(" User keys:");
|
||||
try {
|
||||
pw.println(FileUtils.readTextFile(new File("/data/misc/adb/adb_keys"), 0, null));
|
||||
} catch (IOException e) {
|
||||
pw.println("IOException: " + e);
|
||||
}
|
||||
pw.println(" System keys:");
|
||||
try {
|
||||
pw.println(FileUtils.readTextFile(new File("/adb_keys"), 0, null));
|
||||
} catch (IOException e) {
|
||||
pw.println("IOException: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,6 +114,7 @@ public class UsbDeviceManager {
|
||||
private boolean mAudioSourceEnabled;
|
||||
private Map<String, List<Pair<String, String>>> mOemModeMap;
|
||||
private String[] mAccessoryStrings;
|
||||
private UsbDebuggingManager mDebuggingManager;
|
||||
|
||||
private class AdbSettingsObserver extends ContentObserver {
|
||||
public AdbSettingsObserver() {
|
||||
@@ -166,6 +167,10 @@ public class UsbDeviceManager {
|
||||
if (DEBUG) Slog.d(TAG, "accessory attached at boot");
|
||||
startAccessoryMode();
|
||||
}
|
||||
|
||||
if ("1".equals(SystemProperties.get("ro.adb.secure"))) {
|
||||
mDebuggingManager = new UsbDebuggingManager(context);
|
||||
}
|
||||
}
|
||||
|
||||
public void systemReady() {
|
||||
@@ -425,6 +430,9 @@ public class UsbDeviceManager {
|
||||
setEnabledFunctions(mDefaultFunctions, true);
|
||||
updateAdbNotification();
|
||||
}
|
||||
if (mDebuggingManager != null) {
|
||||
mDebuggingManager.setAdbEnabled(mAdbEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
private void setEnabledFunctions(String functions, boolean makeDefault) {
|
||||
@@ -601,6 +609,9 @@ public class UsbDeviceManager {
|
||||
if (mCurrentAccessory != null) {
|
||||
mSettingsManager.accessoryAttached(mCurrentAccessory);
|
||||
}
|
||||
if (mDebuggingManager != null) {
|
||||
mDebuggingManager.setAdbEnabled(mAdbEnabled);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -802,10 +813,25 @@ public class UsbDeviceManager {
|
||||
return usbFunctions;
|
||||
}
|
||||
|
||||
public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
|
||||
if (mDebuggingManager != null) {
|
||||
mDebuggingManager.allowUsbDebugging(alwaysAllow, publicKey);
|
||||
}
|
||||
}
|
||||
|
||||
public void denyUsbDebugging() {
|
||||
if (mDebuggingManager != null) {
|
||||
mDebuggingManager.denyUsbDebugging();
|
||||
}
|
||||
}
|
||||
|
||||
public void dump(FileDescriptor fd, PrintWriter pw) {
|
||||
if (mHandler != null) {
|
||||
mHandler.dump(fd, pw);
|
||||
}
|
||||
if (mDebuggingManager != null) {
|
||||
mDebuggingManager.dump(fd, pw);
|
||||
}
|
||||
}
|
||||
|
||||
private native String[] nativeGetAccessoryStrings();
|
||||
|
||||
@@ -164,6 +164,16 @@ public class UsbService extends IUsbManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
||||
mDeviceManager.allowUsbDebugging(alwaysAllow, publicKey);
|
||||
}
|
||||
|
||||
public void denyUsbDebugging() {
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
|
||||
mDeviceManager.denyUsbDebugging();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
|
||||
|
||||
Reference in New Issue
Block a user