Quản lý nhiều người dùng

Hướng dẫn dành cho nhà phát triển này giải thích cách trình kiểm soát chính sách thiết bị (DPC) có thể quản lý nhiều người dùng Android trên thiết bị chuyên dụng.

Tổng quan

DPC của bạn có thể giúp nhiều người dùng chung một thiết bị chuyên dụng. DPC của bạn chạy trên một thiết bị được quản lý toàn bộ có thể tạo và quản lý 2 loại người dùng:

  • Người dùng phụ là người dùng Android có các ứng dụng và dữ liệu riêng biệt được lưu giữa các phiên. Bạn quản lý người dùng bằng thành phần quản trị viên. Những người dùng này rất hữu ích trong các trường hợp thiết bị được đến khi bắt đầu ca làm việc, chẳng hạn như trình điều khiển phân phối hoặc nhân viên bảo mật.
  • Người dùng tạm thời là người dùng phụ mà hệ thống sẽ xoá khi người dùng dừng, chuyển đi hoặc thiết bị khởi động lại. Những người dùng này hữu ích cho các trường hợp dữ liệu có thể bị xoá sau khi phiên kết thúc, chẳng hạn như các quầy Internet truy cập công cộng.

Bạn sẽ sử dụng DPC hiện có để quản lý thiết bị chuyên dụng và người dùng phụ. Một thành phần quản trị trong DPC sẽ tự đặt mình làm quản trị viên cho người dùng phụ mới khi bạn tạo họ.

Người dùng chính và 2 người dùng phụ.
Hình 1. Người dùng chính và người dùng phụ do quản trị viên quản lý từ cùng một DPC

Quản trị viên của người dùng phụ phải thuộc cùng một gói với quản trị viên của thiết bị được quản lý hoàn toàn. Để đơn giản hoá quá trình phát triển, bạn nên chia sẻ quyền quản trị giữa thiết bị và người dùng phụ.

Việc quản lý nhiều người dùng trên các thiết bị chuyên dụng thường yêu cầu Android 9.0, tuy nhiên một số phương thức dùng trong hướng dẫn của nhà phát triển này lại có trong các phiên bản Android cũ.

Tạo người dùng

DPC của bạn có thể tạo thêm người dùng ở chế độ nền, sau đó chuyển họ sang nền trước. Quy trình này gần như giống nhau đối với cả người dùng phụ và người dùng tạm thời. Triển khai các bước sau đây trong phần quản trị của thiết bị được quản lý hoàn toàn và của người dùng phụ:

  1. Gọi DevicePolicyManager.createAndManageUser(). Để tạo người dùng tạm thời, hãy đưa MAKE_USER_EPHEMERAL vào đối số cờ.
  2. Gọi DevicePolicyManager.startUserInBackground() để bắt đầu người dùng ở chế độ nền. Người dùng bắt đầu chạy nhưng bạn muốn hoàn tất quá trình thiết lập trước khi đưa người dùng lên nền trước và hiện ứng dụng đó cho người dùng thiết bị.
  3. Trong phần quản trị của người dùng phụ, hãy gọi DevicePolicyManager.setAffiliationIds() để liên kết người dùng mới với người dùng chính. Xem phần Phối hợp DPC ở bên dưới.
  4. Quay lại trang quản trị của thiết bị được quản lý toàn bộ, gọi DevicePolicyManager.switchUser() để chuyển người dùng sang nền trước.

Mẫu sau đây cho biết cách bạn có thể thêm bước 1 vào DPC của mình:

Kotlin

val dpm = getContext().getSystemService(Context.DEVICE_POLICY_SERVICE)
        as DevicePolicyManager

// If possible, reuse an existing affiliation ID across the
// primary user and (later) the ephemeral user.
val identifiers = dpm.getAffiliationIds(adminName)
if (identifiers.isEmpty()) {
    identifiers.add(UUID.randomUUID().toString())
    dpm.setAffiliationIds(adminName, identifiers)
}

// Pass an affiliation ID to the ephemeral user in the admin extras.
val adminExtras = PersistableBundle()
adminExtras.putString(AFFILIATION_ID_KEY, identifiers.first())
// Include any other config for the new user here ...

// Create the ephemeral user, using this component as the admin.
try {
    val ephemeralUser = dpm.createAndManageUser(
            adminName,
            "tmp_user",
            adminName,
            adminExtras,
            DevicePolicyManager.MAKE_USER_EPHEMERAL or
                    DevicePolicyManager.SKIP_SETUP_WIZARD)

} catch (e: UserManager.UserOperationException) {
    if (e.userOperationResult ==
            UserManager.USER_OPERATION_ERROR_MAX_USERS) {
        // Find a way to free up users...
    }
}

Java

DevicePolicyManager dpm = (DevicePolicyManager)
    getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);

// If possible, reuse an existing affiliation ID across the
// primary user and (later) the ephemeral user.
Set<String> identifiers = dpm.getAffiliationIds(adminName);
if (identifiers.isEmpty()) {
  identifiers.add(UUID.randomUUID().toString());
  dpm.setAffiliationIds(adminName, identifiers);
}

// Pass an affiliation ID to the ephemeral user in the admin extras.
PersistableBundle adminExtras = new PersistableBundle();
adminExtras.putString(AFFILIATION_ID_KEY, identifiers.iterator().next());
// Include any other config for the new user here ...

// Create the ephemeral user, using this component as the admin.
try {
  UserHandle ephemeralUser = dpm.createAndManageUser(
      adminName,
      "tmp_user",
      adminName,
      adminExtras,
      DevicePolicyManager.MAKE_USER_EPHEMERAL |
          DevicePolicyManager.SKIP_SETUP_WIZARD);

} catch (UserManager.UserOperationException e) {
  if (e.getUserOperationResult() ==
      UserManager.USER_OPERATION_ERROR_MAX_USERS) {
    // Find a way to free up users...
  }
}

Khi tạo hoặc bắt đầu một người dùng mới, bạn có thể kiểm tra lý do của mọi lỗi bằng cách phát hiện trường hợp ngoại lệ UserOperationException và gọi getUserOperationResult(). Vượt quá giới hạn người dùng là những lý do phổ biến gây ra lỗi:

Quá trình tạo người dùng có thể mất chút thời gian. Nếu thường xuyên tạo người dùng, bạn có thể cải thiện trải nghiệm người dùng bằng cách chuẩn bị một người dùng sẵn sàng sử dụng ở chế độ nền. Bạn có thể cần cân bằng các ưu điểm của người dùng sẵn sàng sử dụng với số lượng người dùng tối đa được phép trên thiết bị.

Phát triển mối đồng cảm

Sau khi tạo người dùng mới, bạn nên tham chiếu đến người dùng bằng một số sê-ri cố định. Không duy trì UserHandle vì hệ thống sẽ tái chế các thành phần này khi bạn tạo và xoá người dùng. Lấy số sê-ri bằng cách gọi UserManager.getSerialNumberForUser():

Kotlin

// After calling createAndManageUser() use a device-unique serial number
// (that isn’t recycled) to identify the new user.
secondaryUser?.let {
    val userManager = getContext().getSystemService(UserManager::class.java)
    val ephemeralUserId = userManager!!.getSerialNumberForUser(it)
    // Save the serial number to storage  ...
}

Java

// After calling createAndManageUser() use a device-unique serial number
// (that isn’t recycled) to identify the new user.
if (secondaryUser != null) {
  UserManager userManager = getContext().getSystemService(UserManager.class);
  long ephemeralUserId = userManager.getSerialNumberForUser(secondaryUser);
  // Save the serial number to storage  ...
}

Cấu hình người dùng

Tuỳ thuộc vào nhu cầu của người dùng, bạn có thể tuỳ chỉnh cách thiết lập người dùng phụ. Bạn có thể đưa vào các cờ sau khi gọi createAndManageUser():

SKIP_SETUP_WIZARD
Bỏ qua bước chạy trình hướng dẫn thiết lập người dùng mới nhằm kiểm tra và cài đặt bản cập nhật, nhắc người dùng thêm Tài khoản Google cùng với các dịch vụ của Google và đặt phương thức khoá màn hình. Quá trình này có thể mất chút thời gian và có thể không áp dụng được cho một số người dùng, chẳng hạn như các kiosk Internet công cộng.
LEAVE_ALL_SYSTEM_APPS_ENABLED
Bật chế độ bật tất cả các ứng dụng hệ thống trong chế độ người dùng mới. Nếu bạn không đặt cờ này, người dùng mới sẽ chỉ chứa nhóm ứng dụng tối thiểu mà điện thoại cần để hoạt động – thường là trình duyệt tệp, trình quay số điện thoại, danh bạ và tin nhắn SMS.

Theo dõi vòng đời của người dùng

DPC của bạn (nếu là quản trị viên của thiết bị được quản lý toàn bộ) có thể thấy hữu ích khi biết thời điểm người dùng phụ thay đổi. Để chạy các tác vụ tiếp theo sau khi thay đổi, hãy ghi đè các phương thức gọi lại này trong lớp con DeviceAdminReceiver của DPC:

onUserStarted()
Được gọi sau khi hệ thống khởi động một người dùng. Người dùng này có thể vẫn đang thiết lập hoặc đang chạy trong nền. Bạn có thể lấy người dùng từ đối số startedUser.
onUserSwitched()
Được gọi sau khi hệ thống chuyển sang một người dùng khác. Bạn có thể lấy người dùng mới hiện đang chạy ở nền trước từ đối số switchedUser.
onUserStopped()
Được gọi sau khi hệ thống dừng một người dùng vì họ đã đăng xuất, chuyển sang một người dùng mới (nếu người dùng tạm thời) hoặc DPC của bạn đã dừng người dùng. Bạn có thể lấy người dùng qua đối số stoppedUser.
onUserAdded()
Được gọi khi hệ thống thêm một người dùng mới. Thông thường, người dùng phụ không được thiết lập đầy đủ khi DPC nhận được lệnh gọi lại. Bạn có thể lấy người dùng từ đối số newUser.
onUserRemoved()
Được gọi sau khi hệ thống xoá một người dùng. Vì người dùng này đã bị xoá, nên bạn không thể truy cập vào người dùng được đại diện bằng đối số removedUser.

Để biết thời điểm hệ thống đưa người dùng lên nền trước hoặc chuyển người dùng sang chế độ nền, các ứng dụng có thể đăng ký bộ thu cho các thông báo ACTION_USER_FOREGROUNDACTION_USER_BACKGROUND.

Khám phá người dùng

Để có tất cả người dùng phụ, quản trị viên của thiết bị được quản lý toàn bộ có thể gọi DevicePolicyManager.getSecondaryUsers(). Kết quả bao gồm mọi người dùng phụ hoặc tạm thời do quản trị viên tạo. Kết quả cũng bao gồm mọi người dùng phụ (hoặc người dùng khách) mà một người sử dụng thiết bị có thể đã tạo. Kết quả không bao gồm hồ sơ công việc vì họ không phải là người dùng phụ. Mẫu sau đây cho biết cách bạn có thể sử dụng phương thức này:

Kotlin

// The device is stored for the night. Stop all running secondary users.
dpm.getSecondaryUsers(adminName).forEach {
    dpm.stopUser(adminName, it)
}

Java

// The device is stored for the night. Stop all running secondary users.
for (UserHandle user : dpm.getSecondaryUsers(adminName)) {
  dpm.stopUser(adminName, user);
}

Dưới đây là những phương thức khác mà bạn có thể gọi để tìm hiểu trạng thái của người dùng phụ:

DevicePolicyManager.isEphemeralUser()
Gọi phương thức này từ quản trị viên của người dùng phụ để tìm hiểu xem đây có phải là người dùng tạm thời hay không.
DevicePolicyManager.isAffiliatedUser()
Gọi phương thức này từ quản trị viên của người dùng phụ để tìm hiểu xem người dùng này có được liên kết với người dùng chính hay không. Để tìm hiểu thêm về mối liên kết, hãy xem phần điều phối DPC ở bên dưới.

Quản lý người dùng

Nếu muốn quản lý hoàn toàn vòng đời của người dùng, bạn có thể gọi API để kiểm soát chi tiết thời điểm và cách thiết bị thay đổi người dùng. Ví dụ: bạn có thể xoá người dùng khi bạn không sử dụng thiết bị trong một khoảng thời gian hoặc bạn có thể gửi bất kỳ đơn đặt hàng nào chưa gửi tới máy chủ trước khi ca làm việc của người dùng kết thúc.

Đăng xuất

Android 9.0 đã thêm nút đăng xuất vào màn hình khoá để một người sử dụng thiết bị có thể kết thúc phiên của họ. Sau khi nhấn vào nút này, hệ thống sẽ dừng người dùng phụ, xoá người dùng đó nếu là tạm thời và người dùng chính quay lại nền trước. Android ẩn nút này khi người dùng chính ở nền trước vì người dùng chính không thể đăng xuất.

Theo mặc định, Android không hiển thị nút phiên kết thúc, nhưng quản trị viên của bạn (của một thiết bị được quản lý hoàn toàn) có thể bật nút này bằng cách gọi DevicePolicyManager.setLogoutEnabled(). Nếu bạn cần xác nhận trạng thái hiện tại của nút, hãy gọi DevicePolicyManager.isLogoutEnabled().

Quản trị viên của người dùng phụ có thể đăng xuất người dùng và quay lại người dùng chính theo phương thức lập trình. Trước tiên, hãy xác nhận người dùng phụ và người dùng chính đã được liên kết, sau đó gọi DevicePolicyManager.logoutUser(). Nếu người dùng đăng xuất là người dùng tạm thời, hệ thống sẽ dừng rồi xoá người dùng đó.

Chuyển đổi người dùng

Để chuyển sang một người dùng phụ khác, quản trị viên của thiết bị được quản lý toàn bộ có thể gọi DevicePolicyManager.switchUser(). Để thuận tiện, bạn có thể truyền null để chuyển sang người dùng chính.

Dừng một người dùng

Để dừng một người dùng phụ, DPC sở hữu thiết bị được quản lý toàn bộ có thể gọi DevicePolicyManager.stopUser(). Nếu người dùng bị dừng là người dùng tạm thời, thì người dùng đó sẽ bị dừng rồi bị xoá.

Bạn nên dừng người dùng bất cứ khi nào có thể để giúp duy trì dưới số lượng người dùng đang chạy tối đa của thiết bị.

Xóa người dùng

Để xoá vĩnh viễn một người dùng phụ, DPC có thể gọi một trong các phương thức DevicePolicyManager sau:

  • Quản trị viên của thiết bị được quản lý toàn bộ có thể gọi removeUser().
  • Quản trị viên của người dùng phụ có thể gọi wipeData().

Hệ thống sẽ xoá người dùng tạm thời khi họ đăng xuất, ngừng hoạt động hoặc rời khỏi ứng dụng.

Tắt giao diện người dùng mặc định

Nếu DPC cung cấp giao diện người dùng để quản lý người dùng, bạn có thể tắt giao diện nhiều người dùng tích hợp sẵn của Android. Bạn có thể thực hiện việc này bằng cách gọi DevicePolicyManager.setLogoutEnabled() và thêm quy tắc hạn chế DISALLOW_USER_SWITCH như trong ví dụ sau:

Kotlin

// Explicitly disallow logging out using Android UI (disabled by default).
dpm.setLogoutEnabled(adminName, false)

// Disallow switching users in Android's UI. This DPC can still
// call switchUser() to manage users.
dpm.addUserRestriction(adminName, UserManager.DISALLOW_USER_SWITCH)

Java

// Explicitly disallow logging out using Android UI (disabled by default).
dpm.setLogoutEnabled(adminName, false);

// Disallow switching users in Android's UI. This DPC can still
// call switchUser() to manage users.
dpm.addUserRestriction(adminName, UserManager.DISALLOW_USER_SWITCH);

Người sử dụng thiết bị không thể thêm người dùng phụ bằng giao diện người dùng tích hợp sẵn của Android vì quản trị viên của các thiết bị được quản lý toàn bộ sẽ tự động thêm quy tắc hạn chế người dùng DISALLOW_ADD_USER.

Thông báo trong phiên

Khi người dùng thiết bị chuyển sang người dùng mới, Android sẽ hiển thị một bảng điều khiển để làm nổi bật nút chuyển đó. Android sẽ hiện các thông báo sau:

  • Thông báo về phiên bắt đầu của người dùng hiển thị khi thiết bị chuyển từ người dùng chính sang người dùng phụ.
  • Thông báo về phiên hoạt động của người dùng cuối xuất hiện khi thiết bị của một người dùng phụ quay lại người dùng chính.

Hệ thống không hiển thị thông báo khi chuyển đổi giữa hai người dùng phụ.

Vì các thông báo có thể không phù hợp với một số tình huống nên bạn có thể thay đổi nội dung của các thông báo này. Ví dụ: nếu giải pháp của bạn sử dụng các phiên người dùng tạm thời, bạn có thể phản ánh điều này trong các thông báo như: Dừng phiên trình duyệt và xoá dữ liệu cá nhân...

Hệ thống chỉ hiển thị thông báo trong vài giây, vì vậy, mỗi thông báo phải là một cụm từ ngắn và rõ ràng. Để tuỳ chỉnh thông báo, quản trị viên có thể gọi các phương thức DevicePolicyManager setStartUserSessionMessage()setEndUserSessionMessage() như minh hoạ trong ví dụ sau:

Kotlin

// Short, easy-to-read messages shown at the start and end of a session.
// In your app, store these strings in a localizable resource.
internal val START_USER_SESSION_MESSAGE = "Starting guest session…"
internal val END_USER_SESSION_MESSAGE = "Stopping & clearing data…"

// ...
dpm.setStartUserSessionMessage(adminName, START_USER_SESSION_MESSAGE)
dpm.setEndUserSessionMessage(adminName, END_USER_SESSION_MESSAGE)

Java

// Short, easy-to-read messages shown at the start and end of a session.
// In your app, store these strings in a localizable resource.
private static final String START_USER_SESSION_MESSAGE = "Starting guest session…";
private static final String END_USER_SESSION_MESSAGE = "Stopping & clearing data…";

// ...
dpm.setStartUserSessionMessage(adminName, START_USER_SESSION_MESSAGE);
dpm.setEndUserSessionMessage(adminName, END_USER_SESSION_MESSAGE);

Truyền null để xoá các thông báo tuỳ chỉnh và quay lại các thông báo mặc định của Android. Nếu bạn cần kiểm tra nội dung tin nhắn hiện tại, hãy gọi getStartUserSessionMessage() hoặc getEndUserSessionMessage().

DPC của bạn phải đặt thông báo đã bản địa hoá theo ngôn ngữ hiện tại của người dùng. Bạn cũng cần cập nhật thông báo khi ngôn ngữ của người dùng thay đổi:

Kotlin

override fun onReceive(context: Context?, intent: Intent?) {
    // Added the <action android:name="android.intent.action.LOCALE_CHANGED" />
    // intent filter for our DeviceAdminReceiver subclass in the app manifest file.
    if (intent?.action === ACTION_LOCALE_CHANGED) {

        // Android's resources return a string suitable for the new locale.
        getManager(context).setStartUserSessionMessage(
                getWho(context),
                context?.getString(R.string.start_user_session_message))

        getManager(context).setEndUserSessionMessage(
                getWho(context),
                context?.getString(R.string.end_user_session_message))
    }
    super.onReceive(context, intent)
}

Java

public void onReceive(Context context, Intent intent) {
  // Added the <action android:name="android.intent.action.LOCALE_CHANGED" />
  // intent filter for our DeviceAdminReceiver subclass in the app manifest file.
  if (intent.getAction().equals(ACTION_LOCALE_CHANGED)) {

    // Android's resources return a string suitable for the new locale.
    getManager(context).setStartUserSessionMessage(
        getWho(context),
        context.getString(R.string.start_user_session_message));

    getManager(context).setEndUserSessionMessage(
        getWho(context),
        context.getString(R.string.end_user_session_message));
  }
  super.onReceive(context, intent);
}

Điều phối DPC

Việc quản lý người dùng phụ thường cần 2 thực thể của DPC — một thực thể sở hữu thiết bị được quản lý hoàn toàn trong khi bản còn lại sở hữu người dùng phụ. Khi tạo người dùng mới, quản trị viên của thiết bị được quản lý hoàn toàn sẽ đặt một thực thể khác của chính mình làm quản trị viên của người dùng mới.

Người dùng liên kết

Một số API trong hướng dẫn dành cho nhà phát triển này chỉ hoạt động khi người dùng phụ được liên kết. Vì Android vô hiệu hoá một số tính năng (ví dụ: ghi nhật ký mạng) khi bạn thêm người dùng phụ mới chưa liên kết vào thiết bị, bạn nên liên kết người dùng càng sớm càng tốt. Hãy xem ví dụ trong phần Thiết lập bên dưới.

Thiết lập

Thiết lập người dùng phụ mới (từ DPC sở hữu người dùng phụ) trước khi cho phép mọi người sử dụng những người dùng đó. Bạn có thể thực hiện việc thiết lập này thông qua lệnh gọi lại DeviceAdminReceiver.onEnabled(). Nếu trước đây bạn đã đặt bất kỳ phần bổ sung quản trị nào trong lệnh gọi đến createAndManageUser(), thì bạn có thể nhận các giá trị từ đối số intent. Ví dụ sau đây cho thấy một DPC liên kết với một người dùng phụ mới trong lệnh gọi lại:

Kotlin

override fun onEnabled(context: Context?, intent: Intent?) {
    super.onEnabled(context, intent)

    // Get the affiliation ID (our DPC previously put in the extras) and
    // set the ID for this new secondary user.
    intent?.getStringExtra(AFFILIATION_ID_KEY)?.let {
        val dpm = getManager(context)
        dpm.setAffiliationIds(getWho(context), setOf(it))
    }
    // Continue setup of the new secondary user ...
}

Java

public void onEnabled(Context context, Intent intent) {
  // Get the affiliation ID (our DPC previously put in the extras) and
  // set the ID for this new secondary user.
  String affiliationId = intent.getStringExtra(AFFILIATION_ID_KEY);
  if (affiliationId != null) {
    DevicePolicyManager dpm = getManager(context);
    dpm.setAffiliationIds(getWho(context),
        new HashSet<String>(Arrays.asList(affiliationId)));
  }
  // Continue setup of the new secondary user ...
}

RPC giữa các DPC

Mặc dù 2 thực thể DPC đang chạy dưới những người dùng riêng biệt, nhưng DPC sở hữu thiết bị và người dùng phụ có thể giao tiếp với nhau. Vì việc gọi dịch vụ của một DPC khác vượt qua ranh giới người dùng, nên DPC của bạn không thể gọi bindService() như bình thường trong Android. Để liên kết với một dịch vụ đang chạy trong người dùng khác, hãy gọi DevicePolicyManager.bindDeviceAdminServiceAsUser().

Người dùng chính và 2 người dùng phụ được liên kết đang gọi RPC.
Hình 2. Quản trị viên của những người dùng chính và phụ được liên kết, các phương thức dịch vụ gọi

DPC của bạn chỉ có thể liên kết với các dịch vụ đang chạy trong những người dùng do DevicePolicyManager.getBindDeviceAdminTargetUsers() trả về. Ví dụ sau đây cho thấy quản trị viên của liên kết người dùng phụ với quản trị viên của thiết bị được quản lý hoàn toàn:

Kotlin

// From a secondary user, the list contains just the primary user.
dpm.getBindDeviceAdminTargetUsers(adminName).forEach {

    // Set up the callbacks for the service connection.
    val intent = Intent(mContext, FullyManagedDeviceService::class.java)
    val serviceconnection = object : ServiceConnection {
        override fun onServiceConnected(componentName: ComponentName,
                                        iBinder: IBinder) {
            // Call methods on service ...
        }
        override fun onServiceDisconnected(componentName: ComponentName) {
            // Clean up or reconnect if needed ...
        }
    }

    // Bind to the service as the primary user [it].
    val bindSuccessful = dpm.bindDeviceAdminServiceAsUser(adminName,
            intent,
            serviceconnection,
            Context.BIND_AUTO_CREATE,
            it)
}

Java

// From a secondary user, the list contains just the primary user.
List<UserHandle> targetUsers = dpm.getBindDeviceAdminTargetUsers(adminName);
if (targetUsers.isEmpty()) {
  // If the users aren't affiliated, the list doesn't contain any users.
  return;
}

// Set up the callbacks for the service connection.
Intent intent = new Intent(mContext, FullyManagedDeviceService.class);
ServiceConnection serviceconnection = new ServiceConnection() {
  @Override
  public void onServiceConnected(
      ComponentName componentName, IBinder iBinder) {
    // Call methods on service ...
  }

  @Override
  public void onServiceDisconnected(ComponentName componentName) {
    // Clean up or reconnect if needed ...
  }
};

// Bind to the service as the primary user.
UserHandle primaryUser = targetUsers.get(0);
boolean bindSuccessful = dpm.bindDeviceAdminServiceAsUser(
    adminName,
    intent,
    serviceconnection,
    Context.BIND_AUTO_CREATE,
    primaryUser);

Tài nguyên khác

Để tìm hiểu thêm về các thiết bị chuyên dụng, hãy đọc các tài liệu sau: