7

We would like to have an already added restricted user account be the default when we restart our Samsung SM-T580 tablets.

At current we have 2 accounts installed, Admin and User The User is a user with restricted access.

The tablets are rooted

Hope that someone has a solution for our question

2 Answers 2

3
+100

I am suggesting two solutions. Both of them require root access, and both were tested on a OnePlus 6 running Android 10.

Solution #1

Have the following script (let's call it switch-user.sh) run during boot but after the user has entered device decryption credentials (PIN/password)

#!/system/bin/sh

while true; do
        flag=`/system/bin/getprop vold.fbe.decrypted`
        if [ $flag ]; then
                sleep 1;
                /system/bin/am switch-user USER_ID          # replace USER_ID term with restricted user's id
                exit;
        else 
                sleep 1;
        fi
done

What this script does is to continuously check (with a delay of 1 second) whether the user has decrypted the device or not. If yes, switch to the restricted user after one second, or continue to recheck. Since my restricted user's User Id is 10, I used 10 as USER_ID in it. Change it to whatever User Id your restricted user has. See my answer here if you need help in finding out the User Id.

Note: In the above script I am checking for the value of the property vold.fbe.decrypted which works for my OnePlus 6 running Android 10. Your device may or may not have the same property. You can hunt for the relevant property by looking into the output of the command adb shell 'getprop | grep vold'. Alternatively, see if sys.user.0.ce_available property is available in your Android version.

Next thing to do is to put that script into a location in your Android from where the system would execute it on its own during boot. Since I use Magisk, I placed that switch-user.sh script into the directory /data/adb/service.d (see Magisk's Boot Scripts section for further information on it) and added executable permission to it using the command:

adb shell su -c 'chmod +x /data/adb/service.d/switch-user.sh'

If you do not use Magisk, you can take the help from the answers at How can I run a script on boot?

Restart the device to see if your script works. In my case, whenever I enter my PIN to decrypt the device, than within two-three seconds the system automatically switches to my restricted user.


Solution #2

If you don't want the hassle of injecting a script into boot process you can setup an automation app which would switch the Android to your restricted user once it receives BOOT_COMPLETED broadcast, or in other words, do something during startup.

I can suggest Tasker and MacroDroid as I have tried them and they worked on Genymotion with Android 6.0 and on a OnePlus 6 with Android 10. You can try any app which can run a command/script on startup.

Tasker

For Tasker, the profile and the task should be this:

Profile: Event → Device Boot

Task: Code → Run Shell:

  • Command: su 2000 -c am switch-user USER_ID
  • tick Use Root
  • leave the rest of the settings untouched

Make sure to replace USER_ID there with the actual user id of the restricted user.

MacroDroid

For MacroDroid, the Macro should be this:

Trigger: Device Events → Device Boot

Action: Applications → Shell Script:

  • tick Rooted
  • Enter the following command in "Enter script" field: su 2000 -c am switch-user USER_ID
  • leave the rest of the settings untouched

Make sure to replace USER_ID there with the actual user id of the restricted user. See my answer here if you need help in finding out the User Id.

Note: because many apps would be competing to run their XYZ things during startup, you might notice a delay of a couple of seconds before user switching takes place.

0
1

I suggest to add an App that will start at every system start to switch to a secondary user. The method require a version of Android 10 minimum.

Let's suppose that the secondary user is not admin and it's the only secondary user.

Source code:

Manifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.switchuser">

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name="com.example.switchuser.BootReceiver"
            tools:ignore="Instantiatable"
            android:enabled="true"
            android:exported="true"
            android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.ACTION_BOOT_COMPLETED" />
                <action android:name="android.intent.action.REBOOT" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
                <action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
                <action android:name="android.intent.action.ACTION_SHUTDOWN" />
            </intent-filter>
        </receiver>
        <receiver
            android:name=".AppAdminReceiver"
            android:permission="android.permission.BIND_DEVICE_ADMIN">
            <meta-data
                android:name="android.app.device_admin"
                android:resource="@xml/device_admin_receiver" />

            <intent-filter>
                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

res/xml/device_admin_receiver.xml

<?xml version="1.0" encoding="utf-8"?>
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-policies>
        <limit-password />
        <watch-login />
        <reset-password />
        <force-lock />
        <wipe-data />
        <expire-password />
        <encrypted-storage />
        <disable-camera />
        <disable-keyguard-features />
    </uses-policies>
</device-admin>

MainActivity.java

package com.example.switchuser;

import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;

import android.os.UserHandle;
import android.view.View;

import android.view.Menu;
import android.view.MenuItem;

import java.util.List;

public class MainActivity extends AppCompatActivity {
    public static final int RESULT_ENABLE = 11;
    private ComponentName compName;
    private DevicePolicyManager manager;
    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        compName = new ComponentName(this, AppAdminReceiver.class);

        Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
        intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, compName);
        intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "Explain why we need this permission");
        startActivityForResult(intent, RESULT_ENABLE);

        manager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);

        # Get list of secondary users
        List<UserHandle> listUsers = manager.getSecondaryUsers(compName);
        
        #Switch to the first secondary user in the list
        manager.switchUser(compName, listUsers.get(0));


    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

AppAdminReceiver.java

package com.example.switchuser;

import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Build;;
import android.widget.Toast;

import androidx.annotation.RequiresApi;

public class AppAdminReceiver extends DeviceAdminReceiver {

    private static final String TAG = "AppAdminReceiver";
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void onProfileProvisioningComplete(Context context, Intent intent) {
        // Enable the profile
        DevicePolicyManager manager =
                (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);

        ComponentName componentName = this.getComponentName(context);

        manager.setProfileName(componentName, "SwitchUser");

        manager.setLockTaskPackages(componentName, new String[]{"com.example.switchuser"});
    }

    /**
     * @return A newly instantiated {@link ComponentName} for this
     * DeviceAdminReceiver.
     */
    public static ComponentName getComponentName(Context context) {
        return new ComponentName(context.getApplicationContext(), AppAdminReceiver.class);
    }

    @Override
    public void onEnabled(Context context, Intent intent) {
        Toast.makeText(context, "Device Admin : enabled", Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onDisabled(Context context, Intent intent) {
        Toast.makeText(context, "Device Admin : disabled", Toast.LENGTH_SHORT).show();
    }
}

BootReceiver.java

package com.example.switchuser;

import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.UserHandle;

import androidx.annotation.RequiresApi;

import java.util.List;

public class BootReceiver extends BroadcastReceiver {

    private static final String TAG = "Boot Receiver";
    private ComponentName compName;
    private DevicePolicyManager manager;

    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent != null) {
            if (intent.getAction().equalsIgnoreCase(
                    Intent.ACTION_BOOT_COMPLETED)) {

                compName = new ComponentName(context, AppAdminReceiver.class);


                manager = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);

                List<UserHandle> listUsers = manager.getSecondaryUsers(compName);

                manager.switchUser(compName, listUsers.get(0));
            }
        }
    }
}

To enable the application as Device Owner in order have permissions to change the user, we need to use ADB:

adb root
adb shell dpm set-device-owner com.example.switchuser/.AppAdminReceiver

User restriction

In order to harden the user you can:

  1. Dump /data/system/users/10.xml where 10 is the id of the user. The file looks like this:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<user id="10" serialNumber="10" flags="16" created="1598034338552" lastLoggedIn="1598035769294" lastLoggedInFingerprint="Android/sdk_phone_x86_64/generic_x86_64:10/QPP6.190730.005.B1/5775370:userdebug/test-keys" icon="/data/system/users/10/photo.png" profileBadge="0">
    <name>New user</name>
    <restrictions no_sms="true" no_outgoing_calls="true" />
</user>
  1. Add more restrictions. The list of restrictions can be founded on UserManager Documentation
  2. push the changes
adb push 10.xml /data/system/users/10.xml

Reboot

Once the device start the application switch the user to the secondary user.

Tests

The app was tested on AVD (Android Virtual Device)

Source code on github

1
  • 1
    Hi! I appreciate the source code for the app, but considering Android Enthusiasts Stack Exchange focuses on Android end-users (but not necessarily developers), I'm afraid this answer is a bit too much for the majority of end-users and out-of-scope of this site. Considering that the source code is already on GitHub, I'd suggest removing the source code and providing the link to the APK instead so that non-dev end-users can use it directly, and dev-users can still build it from GitHub if they want. Thanks!
    – Andrew T.
    Aug 23, 2020 at 9:06

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .