Mengelola beberapa pengguna

Panduan developer ini menjelaskan bagaimana pengontrol kebijakan perangkat (DPC) Anda dapat mengelola beberapa pengguna Android di perangkat khusus.

Ringkasan

DPC dapat membantu beberapa orang berbagi satu perangkat khusus. DPC Anda berjalan di perangkat terkelola sepenuhnya dapat membuat dan mengelola dua jenis pengguna:

  • Pengguna sekunder adalah pengguna Android yang menyimpan aplikasi dan data terpisah antar sesi. Anda mengelola pengguna dengan komponen admin. Para pengguna ini berguna untuk kasus di mana perangkat diambil ketika {i>shift<i} bekerja, seperti pengemudi pengiriman atau petugas keamanan.
  • Pengguna ephemeral adalah pengguna sekunder yang dihapus oleh sistem saat pengguna berhenti, beralih, atau perangkat dimulai ulang. Para pengguna ini berguna dalam berbagai kasus di mana data dapat dihapus setelah sesi selesai, seperti akses publik kios internet.

Anda menggunakan DPC yang ada untuk mengelola perangkat khusus dan DPC sekunder pelanggan. Komponen admin di DPC menetapkan dirinya sendiri sebagai admin untuk fitur sekunder baru pengguna saat Anda membuatnya.

Pengguna utama dan dua pengguna sekunder.
Gambar 1. Pengguna utama dan sekunder yang dikelola oleh admin dari DPC yang sama

Admin pengguna sekunder harus berada dalam paket yang sama dengan admin pengguna merupakan perangkat yang terkelola sepenuhnya. Untuk menyederhanakan pengembangan, sebaiknya Anda membagikan informasi antara perangkat dan pengguna sekunder.

Mengelola banyak pengguna pada perangkat khusus biasanya memerlukan Android 9.0, namun beberapa metode yang digunakan dalam panduan pengembang ini tersedia di Android versi sebelumnya.

Pengguna sekunder

Pengguna sekunder dapat terhubung ke Wi-Fi dan dapat mengonfigurasi jaringan baru. Namun, mereka tidak dapat mengedit atau menghapus jaringan, bahkan jaringan yang mereka buat.

Membuat pengguna

DPC dapat membuat pengguna tambahan di latar belakang dan kemudian dapat mengalihkannya ke latar depan. Prosesnya hampir sama, baik untuk sekunder maupun {i>ephemeral user<i}. Terapkan langkah-langkah berikut untuk Admin perangkat terkelola dan pengguna sekunder:

  1. Panggil DevicePolicyManager.createAndManageUser(). Untuk membuat pengguna efemeral, sertakan MAKE_USER_EPHEMERAL dalam argumen flag.
  2. Telepon DevicePolicyManager.startUserInBackground() ke memulai aktivitas pengguna di latar belakang. Pengguna mulai berlari tetapi Anda perlu untuk menyelesaikan penyiapan sebelum membawa pengguna ke latar depan dan menampilkannya kepada pengguna yang menggunakan perangkat.
  3. Pada admin pengguna sekunder, panggil DevicePolicyManager.setAffiliationIds() ke mengafiliasi pengguna baru dengan pengguna utama. Lihat Koordinasi DPC di bawah.
  4. Kembali ke admin perangkat terkelola sepenuhnya, panggil DevicePolicyManager.switchUser() untuk mengalihkan pengguna ke latar depan.

Contoh berikut menunjukkan cara menambahkan langkah 1 ke DPC:

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...
  }
}

Saat membuat atau memulai pengguna baru, Anda dapat memeriksa alasan kegagalan dengan mengambil pengecualian UserOperationException dan memanggil getUserOperationResult(). Melebihi jumlah pengguna batas adalah alasan kegagalan yang umum:

Membuat pengguna dapat memerlukan waktu beberapa saat. Jika Anda sering membuat pengguna, Anda dapat meningkatkan pengalaman pengguna dengan menyiapkan pengguna yang siap digunakan di latar belakang. Anda mungkin perlu menyeimbangkan keuntungan dari pengguna yang siap pakai dengan jumlah pengguna yang diizinkan di suatu perangkat.

Identifikasi

Setelah membuat pengguna baru, Anda harus merujuk ke pengguna dengan angka Jangan mempertahankan UserHandle karena sistem mendaur ulangnya saat Anda membuat dan menghapus pengguna. Dapatkan nomor seri dengan memanggil 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  ...
}

Konfigurasi pengguna

Bergantung pada kebutuhan pengguna, Anda dapat menyesuaikan penyiapan pelanggan. Anda dapat menyertakan tanda berikut saat memanggil createAndManageUser():

SKIP_SETUP_WIZARD
Melewati menjalankan wizard penyiapan pengguna baru yang memeriksa dan menginstal update, meminta pengguna untuk menambahkan Akun Google beserta layanan Google, dan menetapkan kunci layar. Proses ini dapat memerlukan waktu beberapa saat dan mungkin tidak berlaku untuk semua pengguna pengguna—misalnya kios internet publik.
LEAVE_ALL_SYSTEM_APPS_ENABLED
Membiarkan semua aplikasi sistem tetap aktif di pengguna baru. Jika Anda tidak menetapkan penanda ini, pengguna baru hanya berisi serangkaian aplikasi minimal yang diperlukan ponsel beroperasi—biasanya {i>file browser<i}, telepon telepon, kontak, dan pesan SMS.

Mengikuti siklus proses pengguna

DPC (jika admin perangkat terkelola sepenuhnya) mungkin merasa terbantu untuk mengetahui kapan pengguna sekunder berubah. Untuk menjalankan tugas lanjutan setelah perubahan, ganti metode callback berikut di subclass DeviceAdminReceiver DPC:

onUserStarted()
Dipanggil setelah sistem memulai pengguna. Pengguna ini mungkin masih menyiapkan atau berjalan di latar belakang. Anda bisa mendapatkan pengguna dari startedUser argumen.
onUserSwitched()
Dipanggil setelah sistem beralih ke pengguna lain. Anda bisa mendapatkan pengguna baru yang sekarang berjalan di latar depan dari argumen switchedUser.
onUserStopped()
Dipanggil setelah sistem menghentikan pengguna karena mereka telah logout, beralih ke pengguna baru (jika pengguna bersifat sementara), atau DPC menghentikan pengguna. Anda bisa mendapatkan pengguna dari argumen stoppedUser.
onUserAdded()
Dipanggil saat sistem menambahkan pengguna baru. Biasanya, pengguna sekunder tidak sudah disiapkan sepenuhnya ketika DPC mendapatkan callback. Anda bisa mendapatkan pengguna dari Argumen newUser.
onUserRemoved()
Dipanggil setelah sistem menghapus pengguna. Karena pengguna sudah dihapus, Anda tidak dapat mengakses pengguna yang diwakili oleh argumen removedUser.

Untuk mengetahui kapan sistem membawa pengguna ke latar depan atau mengirim pengguna ke latar belakang, aplikasi dapat mendaftarkan penerima untuk ACTION_USER_FOREGROUND dan ACTION_USER_BACKGROUND.

Temukan pengguna

Untuk mendapatkan semua pengguna sekunder, admin perangkat terkelola sepenuhnya dapat memanggil DevicePolicyManager.getSecondaryUsers() Hasil termasuk pengguna sekunder atau {i>ephemeral<i} yang dibuat oleh admin. Hasilnya juga termasuk pengguna sekunder (atau pengguna tamu) yang mungkin digunakan seseorang buat. Hasil penelusuran tidak menyertakan profil kerja karena belum pengguna sekunder. Contoh berikut menunjukkan cara menggunakan metode ini:

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);
}

Berikut adalah metode lain yang dapat Anda panggil untuk mengetahui status pengguna sekunder:

DevicePolicyManager.isEphemeralUser()
Panggil metode ini dari admin pengguna sekunder untuk mengetahui apakah ini pengguna singkat.
DevicePolicyManager.isAffiliatedUser()
Panggil metode ini dari admin pengguna sekunder untuk mengetahui apakah pengguna ini berafiliasi dengan pengguna utama. Untuk mempelajari afiliasi lebih lanjut, lihat DPC koordinasi di bawah ini.

Pengelolaan pengguna

Jika Anda ingin mengelola siklus proses pengguna sepenuhnya, Anda dapat memanggil API untuk mengontrol kapan dan bagaimana perangkat mengubah pengguna. Sebagai contoh, Anda dapat menghapus pengguna jika perangkat tidak digunakan selama jangka waktu tertentu atau Anda dapat mengirim pesanan yang tidak terkirim ke server sebelum {i>shift<i} seseorang selesai.

Keluar

Android 9.0 menambahkan tombol {i>log-out<i} ke layar kunci sehingga seseorang yang menggunakan dapat mengakhiri sesinya. Setelah mengetuk tombol tersebut, sistem akan menghentikan pengguna sekunder, menghapus pengguna jika bersifat sementara, dan pengguna utama kembali ke latar depan. Android menyembunyikan tombol saat pengguna utama berada di latar depan karena pengguna utama tidak dapat keluar.

Android tidak menampilkan tombol akhiri sesi secara default, tetapi admin Anda (dari perangkat terkelola sepenuhnya) dapat mengaktifkannya dengan memanggil DevicePolicyManager.setLogoutEnabled() Jika Anda ingin mengkonfirmasi status tombol saat ini, memanggil DevicePolicyManager.isLogoutEnabled()

Admin pengguna sekunder dapat membuat pengguna logout secara terprogram dan kembali kepada pengguna utama. Pertama, pastikan pengguna sekunder dan utama adalah terafiliasi, lalu panggil DevicePolicyManager.logoutUser(). Jika pengguna yang {i>log-out<i} adalah pengguna {i>ephemeral<i}, sistem berhenti dan kemudian menghapus .

Ganti pengguna

Untuk beralih ke pengguna sekunder lain, admin perangkat terkelola sepenuhnya dapat panggil DevicePolicyManager.switchUser(). Untuk memudahkan, Anda dapat meneruskan null untuk beralih ke pengguna utama.

Menghentikan pengguna

Untuk menghentikan pengguna sekunder, DPC yang memiliki perangkat terkelola sepenuhnya dapat memanggil DevicePolicyManager.stopUser() Jika pengguna yang berhenti adalah {i>ephemeral user<i}, pengguna dihentikan kemudian dihapus.

Sebaiknya hentikan pengguna jika memungkinkan agar tetap berada di bawah batas perangkat jumlah maksimum pengguna berjalan.

Menghapus pengguna

Untuk menghapus pengguna sekunder secara permanen, DPC dapat memanggil salah satu Metode DevicePolicyManager:

  • Admin perangkat terkelola sepenuhnya dapat memanggil removeUser().
  • Admin pengguna sekunder dapat memanggil wipeData().

Sistem menghapus pengguna sementara saat mereka logout, dihentikan, atau diganti jauh darinya.

Menonaktifkan UI default

Jika DPC menyediakan UI untuk mengelola pengguna, Anda dapat menonaktifkan fitur bawaan Android {i>multi-user interface<i}. Anda dapat melakukan ini dengan memanggil DevicePolicyManager.setLogoutEnabled() dan menambahkan Pembatasan DISALLOW_USER_SWITCH seperti yang ditunjukkan di contoh berikut:

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);

Pengguna perangkat tidak dapat menambahkan pengguna sekunder dengan UI bawaan Android karena admin perangkat terkelola sepenuhnya akan otomatis menambahkan Batasan pengguna DISALLOW_ADD_USER.

Pesan sesi

Saat pengguna yang menggunakan perangkat beralih ke pengguna baru, Android akan menampilkan panel untuk menyoroti {i>switch<i}. Android akan menampilkan pesan berikut:

  • Pesan sesi pengguna awal ditampilkan saat perangkat beralih ke pesan sekunder dari pengguna utama.
  • Pesan sesi pengguna akhir ditampilkan saat perangkat kembali ke pengguna utama dari pengguna sekunder.

Sistem tidak menampilkan pesan saat beralih di antara dua pengguna sekunder.

Karena pesan mungkin tidak cocok untuk semua situasi, Anda dapat mengubah teks dari pesan tersebut. Misalnya, jika solusi Anda menggunakan pengguna {i>ephemeral<i} Anda dapat merefleksikannya dalam pesan seperti: Menghentikan browser sesi & menghapus data pribadi...

Sistem menampilkan pesan selama beberapa detik, jadi setiap pesan harus berupa frasa yang singkat dan jelas. Untuk menyesuaikan pesan, admin Anda dapat memanggil metode DevicePolicyManager setStartUserSessionMessage() dan setEndUserSessionMessage() seperti yang ditampilkan di contoh berikut:

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);

Teruskan null untuk menghapus pesan kustom Anda dan kembali ke setelan default Android membuat pesan teks. Jika Anda perlu memeriksa teks pesan saat ini, hubungi getStartUserSessionMessage() atau getEndUserSessionMessage().

DPC Anda harus menetapkan pesan yang dilokalkan untuk lokalitas pengguna saat ini. Anda juga perlu memperbarui pesan saat perubahan lokal pengguna:

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);
}

Koordinasi DPC

Mengelola pengguna sekunder biasanya memerlukan dua instance DPC—satu yang memiliki perangkat terkelola sepenuhnya sementara yang lain memiliki pengguna sekunder. Saat membuat pengguna baru, admin perangkat terkelola sepenuhnya menyetel instance lain dirinya sebagai admin pengguna baru.

Pengguna terafiliasi

Beberapa API dalam panduan developer ini hanya berfungsi saat pengguna sekunder berafiliasi. Karena Android menonaktifkan beberapa fitur (misalnya logging jaringan) saat Anda menambahkan pengguna sekunder baru yang tidak terafiliasi ke perangkat itu, Anda harus segera mengafiliasi pengguna sesegera mungkin. Lihat contohnya di Penyiapan di bawah.

Penyiapan

Siapkan pengguna sekunder baru (dari DPC yang memiliki pengguna sekunder) sebelum mengizinkan orang menggunakannya. Anda dapat melakukan pengaturan ini dari Callback DeviceAdminReceiver.onEnabled(). Jika sebelumnya Anda menyetel tambahan admin apa pun dalam panggilan ke createAndManageUser(), Anda bisa mendapatkan nilai dari argumen intent. Contoh berikut menunjukkan DPC yang berafiliasi pengguna sekunder baru di callback:

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 antar-DPC

Meskipun dua instance DPC berjalan di bawah pengguna terpisah, DPC yang memiliki perangkat dan pengguna sekunder dapat berkomunikasi satu sama lain. Karena memanggil layanan DPC lain melewati batas pengguna, DPC Anda tidak bisa hubungi bindService() seperti yang biasa Anda lakukan Android. Untuk mengikat ke layanan yang berjalan di pengguna lain, panggil DevicePolicyManager.bindDeviceAdminServiceAsUser()

Pengguna utama dan dua pengguna sekunder terafiliasi yang memanggil RPC.
Gambar 2. Admin pengguna utama dan sekunder yang berafiliasi memanggil metode layanan

DPC hanya dapat mengikat ke layanan yang berjalan di pengguna yang dikembalikan oleh DevicePolicyManager.getBindDeviceAdminTargetUsers() Contoh berikut menunjukkan admin dari binding pengguna sekunder ke admin dari perangkat terkelola sepenuhnya:

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);

Referensi lainnya

Untuk mempelajari perangkat khusus lebih lanjut, baca dokumen berikut: