DevicePolicyManagerService之DeviceAdmin

Posted Ansen360

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DevicePolicyManagerService之DeviceAdmin相关的知识,希望对你有一定的参考价值。

目录

1.DevicePolicyManagerService的初始化

2.DeviceAdmin


DevicePolicyManagerService是Android提供的一个可管理和操作设备的系统服务,通过DevicePolicyManager为应用层提供操作设备的对应策略.目前推出了三种设备管理方案:Device Administration,Profile Owner,Device Owner.

DeviceAdminandroid2.2中引入,用户可以授权自己的应用设备管理权限后对设备进行一些简单的设置,如锁屏,禁用相机等.由于DeviceAdmin可以由用户授权的任何应用启用,因此它不支持多种企业用例,如防止删除设备管理员,设置恢复出厂设置保护等.

而Android5.0中引入了DeviceOwnerProfileOwner模式,因此设备管理员(DeviceAdmin)已被视为旧版管理方法.由于DeviceAdmin不太适合支持当今的企业要求,因此建议从现在开始采用DeviceOwner和ProfileOwner模式来管理其设备.在Android 9.0版本中弃用了用于企业的设备管理员,并且在Android 10.0版本中将删除这些功能.

1.DevicePolicyManagerService的初始化

Android系统的启动流程大致分为启动BootLoader,Linux kernel,init进程,Zygote进程,SystemServer进程,Launcher进程.而一些java层的系统服务就是在SystemServer进程中启动,包括ActivityManagerService,WindowManagerService,PackageManagerService,DevicePolicyManagerService等.

而DevicePolicyManagerService在SystemServer中的startOtherServices()方法启动,具体如下.

类名SystemServer:

1.1.startOtherServices()

这里是调用SystemServiceManager的startService方法来启动DevicePolicyManagerService.Lifecycle

// android-29\\com\\android\\server\\SystemServer.java
private void startOtherServices() 
	... ...
	// Always start the Device Policy Manager, so that the API is compatible with
	// API8.
	traceBeginAndSlog("StartDevicePolicyManager");
	mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
	traceEnd();
	... ...


类名SystemServiceManager:

1.2.startService()

在SystemServiceManager的start()方法中首先会去判断当前启动的系统服务是否继承自SystemService,否则抛出异常.

随后通过DevicePolicyManagerService.Lifecycle类对象的getConstructor()方法获取构造器对象(Constructor),并调用其newInstance()方法实例化对象;这里调用的是DevicePolicyManagerService.Lifecycle有参构造方法Lifecycle(Context context),而DevicePolicyManagerService类就是在此构造方法中实例化的.

最后继续调用SystemServiceManager的内部方法startService().

	// android-29\\com\\android\\server\\SystemServiceManager.java
    public <T extends SystemService> T startService(Class<T> serviceClass) 
        try 
            final String name = serviceClass.getName();
            Slog.i(TAG, "Starting " + name);
            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);

            // Create the service.
            if (!SystemService.class.isAssignableFrom(serviceClass)) 
                throw new RuntimeException("Failed to create " + name
                        + ": service must extend " + SystemService.class.getName());
            
            final T service;
            try 
                Constructor<T> constructor = serviceClass.getConstructor(Context.class);
                service = constructor.newInstance(mContext);
             catch (InstantiationException ex) 
                throw new RuntimeException("Failed to create service " + name
                        + ": service could not be instantiated", ex);
             catch (IllegalAccessException ex) 
                throw new RuntimeException("Failed to create service " + name
                        + ": service must have a public constructor with a Context argument", ex);
             catch (NoSuchMethodException ex) 
                throw new RuntimeException("Failed to create service " + name
                        + ": service must have a public constructor with a Context argument", ex);
             catch (InvocationTargetException ex) 
                throw new RuntimeException("Failed to create service " + name
                        + ": service constructor threw an exception", ex);
            

            startService(service);
            return service;
         finally 
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
        
    

1.3.startService()

这个方法比较简单,首先把DevicePolicyManagerService.Lifecycle添加到mServices中,mServices是一个存储SystemService类型的ArrayList;然后调用该服务的start()方法.

	// android-29\\com\\android\\server\\SystemServiceManager.java
    public void startService(@NonNull final SystemService service) 
        // Register it.
        mServices.add(service);
        // Start it.
        long time = SystemClock.elapsedRealtime();
        try 
            service.onStart();
         catch (RuntimeException ex) 
            throw new RuntimeException("Failed to start service " + service.getClass().getName()
                    + ": onStart threw an exception", ex);
        
        warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
    

类名:DevicePolicyManagerService.Lifecycle

1.4.onStart()

这里的start方法并不是启动服务,DevicePolicyManagerService在序号2中DevicePolicyManagerService.Lifecycle的构造方法就已经完成实例化,这里主要是把实例化的DPMS(这里的mService也就是实例化的DPMS)和Context.DEVICE_POLICY_SERVICE进行绑定,这样应用程序就可以通过getSystemService(Context.DEVICE_POLICY_SERVICE)来访问到DevicePolicyManagerService.

	// android-29\\com\\android\\server\\devicepolicy\\DevicePolicyManagerService.java
    @Override
    public void onStart() 
        publishBinderService(Context.DEVICE_POLICY_SERVICE, mService);
    

1.5.Lifecycle(Context)

再来看看序号2的DevicePolicyManagerService.Lifecycle构造方法,构造方法代码比较简单,通过反射来获取DevicePolicyManagerService的实例mService.也就是序号4中传入的mService.

	// android-29\\com\\android\\server\\devicepolicy\\DevicePolicyManagerService.Lifecycle.java
	public Lifecycle(Context context) 
        super(context);
        String dpmsClassName = context.getResources()
                .getString(R.string.config_deviceSpecificDevicePolicyManagerService);
        if (TextUtils.isEmpty(dpmsClassName)) 
            dpmsClassName = DevicePolicyManagerService.class.getName();
        
        try 
            Class serviceClass = Class.forName(dpmsClassName);
            Constructor constructor = serviceClass.getConstructor(Context.class);
            mService = (BaseIDevicePolicyManager) constructor.newInstance(context);
         catch (Exception e) 
            throw new IllegalStateException(
                "Failed to instantiate DevicePolicyManagerService with class name: "
                + dpmsClassName, e);
        
    

类名:DevicePolicyManagerService

1.6.DevicePolicyManagerService(Context)

在上面的代码中,通过构造器(Constructor)调用的DevicePolicyManagerService的有参构造DevicePolicyManagerService(Context context),也就是如下方法

    public DevicePolicyManagerService(Context context) 
        this(new Injector(context));
    

1.7.DevicePolicyManagerService(Injector)

DPMS的构造方法中获取一些管理对象如:UserManager,PackageManager,TelephonyManager,注册一些状态和数据改变的监听,实例化一些和DPMS相关的控制类.

DevicePolicyManagerService(Injector injector) 
        mInjector = injector;
        mContext = Preconditions.checkNotNull(injector.mContext);
        mHandler = new Handler(Preconditions.checkNotNull(injector.getMyLooper()));

        mConstantsObserver = new DevicePolicyConstantsObserver(mHandler);
        mConstantsObserver.register();
        mConstants = loadConstants();
		// Owners对象是用来加载和存储device和profile owner的状态
        mOwners = Preconditions.checkNotNull(injector.newOwners());
		// 获取UserManager
        mUserManager = Preconditions.checkNotNull(injector.getUserManager());
        mUserManagerInternal = Preconditions.checkNotNull(injector.getUserManagerInternal());
        mUsageStatsManagerInternal = Preconditions.checkNotNull(
                injector.getUsageStatsManagerInternal());
		// 获取PackageManager
        mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
		// 获取TelephonyManager
        mTelephonyManager = Preconditions.checkNotNull(injector.getTelephonyManager());

        mLocalService = new LocalService();	// 创建DPM本地系统服务
        mLockPatternUtils = injector.newLockPatternUtils();

        // TODO: why does SecurityLogMonitor need to be created even when mHasFeature == false?
        mSecurityLogMonitor = new SecurityLogMonitor(this);

        mHasFeature = mInjector.hasFeature();
        mIsWatch = mInjector.getPackageManager()
                .hasSystemFeature(PackageManager.FEATURE_WATCH);
        mHasTelephonyFeature = mInjector.getPackageManager()
                .hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
        mBackgroundHandler = BackgroundThread.getHandler();

        // Needed when mHasFeature == false, because it controls the certificate warning text.
        mCertificateMonitor = new CertificateMonitor(this, mInjector, mBackgroundHandler);

        mDeviceAdminServiceController = new DeviceAdminServiceController(this, mConstants); //创建设备管理员服务连接的管理类

        mOverlayPackagesProvider = new OverlayPackagesProvider(mContext);

        mTransferOwnershipMetadataManager = mInjector.newTransferOwnershipMetadataManager();

        if (!mHasFeature) 
            // Skip the rest of the initialization
            mSetupContentObserver = null;
            return;
        
		// 注册当前系统用户添加移除等状态变化和package以及时间改变的广播
        IntentFilter filter = new IntentFilter();
 		// ... ...
        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
		// 将mLocalService引用保存到内部集合中,主要是方便其他类获取该对象来对DPM进行操作.
        LocalServices.addService(DevicePolicyManagerInternal.class, mLocalService);

        mSetupContentObserver = new SetupContentObserver(mHandler);

        mUserManagerInternal.addUserRestrictionsListener(new RestrictionsListener(mContext)); // 创建用户限制状态改变的监听
    

2.DeviceAdmin

2.1 开发一个DeviceAdmin设备管理应用

系统管理员可以使用 Device Administration API 来编写一个能够强制执行远程/本地设备安全政策的非系统应用

2.1.1. 配置清单文件

清单文件必须包含以下两个内容:

1. 创建DeviceAdminReceiver的子类,如DeviceAdminSampleReceiver.

2. DeviceAdminReceiver继承自BroadcastReceiver,所以需要在mainfest中添加配置.

同时需要配置android:permission、meta-data和action三个必要属性.

<activity android:name=".app.DeviceAdminSample"
            android:label="@string/activity_sample_device_admin">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.SAMPLE_CODE" />
    </intent-filter>
</activity>
<receiver android:name=".app.DeviceAdminSample$DeviceAdminSampleReceiver"
        android:label="@string/sample_device_admin"
        android:description="@string/sample_device_admin_description"
        android:permission="android.permission.BIND_DEVICE_ADMIN">
    <meta-data android:name="android.app.device_admin"
            android:resource="@xml/device_admin_sample" />
    <intent-filter>
        <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
    </intent-filter>
</receiver>

android:label="@string/activity_sample_device_admin" 指的是 Activity 的用户可读标签

android:label="@string/sample_device_admin" 指的是权限的用户可读标签。

android:description="@string/sample_device_admin_description" 指的是权限的用户可读说明。说明通常比标签长,并且信息更丰富

android:permission="android.permission.BIND_DEVICE_ADMIN" 是 DeviceAdminReceiver 子类必须具有的权限,用于确保仅系统可以与接收者互动(不应向任何应用授予此权限)。该权限可防止其他应用滥用您的设备管理应用

android.app.action.DEVICE_ADMIN_ENABLED 是 DeviceAdminReceiver 子类必须处理才能获准管理设备的主要操作。当用户启用设备管理应用后,系统会针对接收者设置此操作。您的代码通常会在 onEnabled() 中处理此操作。要获得支持,接收者还必须请求 BIND_DEVICE_ADMIN 权限,以防止其他应用滥用

当用户启用设备管理应用后,接收者便会获权执行操作以响应特定系统事件的广播。当发生相应的事件时,应用便可以施加某项政策。例如,如果用户尝试设置不符合政策要求的新密码,应用可以提示用户选择其他符合相应要求的密码

请避免在发布应用后更改接收者名称。如果清单中的名称发生更改,则设备管理会在用户更新应用时停用

android:resource="@xml/device_admin_sample" 可声明元数据中使用的安全政策。元数据提供了特定于设备管理员的其他信息,由 DeviceAdminInfo 类进行解析。下面显示了 device_admin_sample.xml 的内容:

<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 />
      </uses-policies>
    </device-admin>

2.1.2. 代码部分:

2.1.2.1. DeviceAdminReceiver

要创建设备管理应用,必须对 DeviceAdminReceiver 进行子类化。DeviceAdminReceiver 类包含一系列发生特定事件时触发的回调

public class DeviceAdminSample extends DeviceAdminReceiver 

        void showToast(Context context, String msg) 
            String status = context.getString(R.string.admin_receiver_status, msg);
            Toast.makeText(context, status, Toast.LENGTH_SHORT).show();
        

        @Override
        public void onEnabled(Context context, Intent intent) 
            showToast(context, context.getString(R.string.admin_receiver_status_enabled));
        

        @Override
        public CharSequence onDisableRequested(Context context, Intent intent) 
            return context.getString(R.string.admin_receiver_status_disable_warning);
        

        @Override
        public void onDisabled(Context context, Intent intent) 
            showToast(context, context.getString(R.string.admin_receiver_status_disabled));
        

        @Override
        public void onPasswordChanged(Context context, Intent intent, userHandle: UserHandle) 
            showToast(context, context.getString(R.string.admin_receiver_status_pw_changed));
        
    ...
    

相关的系统类:

DevicePolicyManager:

用于管理设备上强制执行的政策的类。此类的大多数客户端必须已经发布了一个用户当前已启用的 DeviceAdminReceiver。DevicePolicyManager 可管理一个或多个 DeviceAdminReceiver 实例的政策

DeviceAdminInfo:

此类用于指定设备管理员组件的元数据

2.1.2.2 激活设备管理员:

通过如下代码跳转到激活设备管理员页面,用户必须明确启用该应用,才能强制执行政策

// 授权页面Action

Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);

intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, deviceAdminSample);

intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,activity.getString(R.string.add_admin_extra_app_text));

startActivityForResult(intent, REQUEST_CODE_ENABLE_ADMIN);

激活设备管理员系统层接口

上述为Android官方推荐的将普通应用设置为DeviceAdmin的方法,其最终会调用到系统DPM的一个接口,具体如下:

DevicePolicyManager应用层接口:

public void setActiveAdmin(@NonNull ComponentName policyReceiver, boolean refreshing) )

该api为隐藏状态,只有系统应用才有权限调用,而普通应用启动action为DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN的activity时会弹出一个框,给用户确认是否激活当前应用设备管理器,如果确认就会调用该隐藏接口激活.该接口又会通过binder调用到系统层DPMS接口,具体如下:

DevicePolicyManagerService系统层接口:

  

    @Override
    public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) 
        if (!mHasFeature) 
            return;
        
        setActiveAdmin(adminReceiver, refreshing, userHandle, null);
    

    private void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle,
            Bundle onEnableData) 
		// 检查调用者的权限 (Android 10 将 MANAGE_DEVICE_ADMINS 权限从签名权限或特许权限更改为
		// 仅签名权限。这意味着仅经平台签名的应用才可将其他应用设置为设备管理员)
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
        enforceFullCrossUsersPermission(userHandle);

        DevicePolicyData policy = getUserData(userHandle); // 获取当前用户的DevicePolicyData,如果不存在就新建一个.
        DeviceAdminInfo info = findAdmin(adminReceiver, userHandle,
                /* throwForMissingPermission= */ true);	// 根据ComponentName创建DeviceAdminInfo
        synchronized (getLockObject()) 
            checkActiveAdminPrecondition(adminReceiver, info, policy);
            long ident = mInjector.binderClearCallingIdentity();
            try 
                final ActiveAdmin existingAdmin
                        = getActiveAdminUncheckedLocked(adminReceiver, userHandle);// 获取系统当前已存在的设备管理员
                if (!refreshing && existingAdmin != null) 	// 如果当前系统存在设备管理员且不需要更新active admin,则抛出异常
                    throw new IllegalArgumentException("Admin is already added");
                
                ActiveAdmin newAdmin = new ActiveAdmin(info, /* parent */ false); // 新建一个设备管理员
                newAdmin.testOnlyAdmin =
                        (existingAdmin != null) ? existingAdmin.testOnlyAdmin
                                : isPackageTestOnly(adminReceiver.getPackageName(), userHandle);
                policy.mAdminMap.put(adminReceiver, newAdmin); 把componentName和ActiveAdmin保存到当前用户的DevicePolicyData的集合中
				// 将新建的设备管理员插入到mAdminList集合中                
				int replaceIndex = -1;
                final int N = policy.mAdminList.size();
                for (int i=0; i < N; i++) 
                    ActiveAdmin oldAdmin = policy.mAdminList.get(i);
                    if (oldAdmin.info.getComponent().equals(adminReceiver)) 
                        replaceIndex = i;
                        break;
                    
                
                if (replaceIndex == -1) 
                    policy.mAdminList.add(newAdmin);
                    enableIfNecessary(info.getPackageName(), userHandle);
                    mUsageStatsManagerInternal.onActiveAdminAdded(
                            adminReceiver.getPackageName(), userHandle);
                 else 
                    policy.mAdminList.set(replaceIndex, newAdmin);
                
                saveSettingsLocked(userHandle);	// 保存当前用户设置到xml中,并发送更改策略的广播
                sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
                        onEnableData, null);	// 发送广播给新的默认设备管理员,也就是DeviceAdminReceiver会接收到广播
             finally 
                mInjector.binderRestoreCallingIdentity(ident);
            
        
    

上面代码首先判断调用应用的权限,只有平台签名的应用才可将其他应用设置为设备管理员,随后主要是在系统中记录当前新设备管理员的信息,以及发送启用新的设备管理员的通知广播ACTION_DEVICE_ADMIN_ENABLED.

2.2 DeviceAdmin的管控能力

设置密码策略:

Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
startActivity(intent); //为设备设置密码,提示用户设置密码的界面
mDevicePolicyManager.setPasswordQuality(mComponentName,DevicePolicyManager.PASSWORD_QUALITY_NUMERIC); //设置密码质量
mDevicePolicyManager.setPasswordMinimumLength(admin, 8); //设置密码最小长度
mDevicePolicyManager.setPasswordMinimumUpperCase(admin, 2); //设置密码内容要求
mDevicePolicyManager.setPasswordHistoryLength(mComponentName, 3); //上述的指定时间内保存多少个密码
mDevicePolicyManager.setPasswordExpirationTimeout(mComponentName, 100); //设置密码的有效期
mDevicePolicyManager.setMaximumFailedPasswordsForWipe(mComponentName, 3); //设置解锁尝试次数
mDevicePolicyManager.getCurrentFailedPasswordAttempts();

设置设备锁定

设置在设备锁定之前,用户可处于不活动状态的时间上限

// 立即锁定

mDevicePolicyManager.lockNow();

// 设置多久后锁定屏幕

long timeMs = 1000L*Long.parseLong(timeout.getText().toString());

mDevicePolicyManager.setMaximumTimeToLock(mComponentName,timeMs);

清除数据

清除所有用户数据。如果作为辅助用户调用,则该用户将被删除,其他用户将不受影响。从主用户调用将导致设备重新启动,在启动时删除所有设备数据(包括所有辅助用户及其数据)

mDevicePolicyManager.wipeData(DevicePolicyManager.WIPE_EXTERNAL_STORAGE);

参数flags一共四个值:

DevicePolicyManager.WIPE_EXTERNAL_STORAGE

同时清除除外存储数据

DevicePolicyManager.WIPE_RESET_PROTECTION_DATA

清除出厂重置保护数据(只允许device owner调用否则抛SecurityException异常)

DevicePolicyManager.WIPE_EUICC

同时清除设备的eUICC数据

DevicePolicyManager.WIPE_SILENTLY

不发出警告的情况下清除数据

还可以使用 setMaximumFailedPasswordsForWipe() 声明在特定错误密码尝试次数后清除设备数据

停用相机

mDevicePolicyManager.setCameraDisabled(mComponentName, true);

设置存储设备加密

对存储的应用数据进行加密

mDevicePolicyManager.setStorageEncryption(mComponentName, true);

更改锁屏密码

mDevicePolicyManager.resetPassword("password",DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY);

参数flags一共两个值:

DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY

admin用户必须进入系统才能重置密码

DevicePolicyManager.RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT

不需要密码重启设备,只能device owner设置

修改锁屏状态特征

是否允许相机、通知等内容

mDevicePolicyManager.setKeyguardDisabledFeatures(admin,DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL);

DevicePolicyManagerService之DeviceOwner和ProfileOwner

官方相关文档1(device-admin)

官方相关文档2(device-admin-deprecation)

官方相关文档3(DeviceOwner)

以上是关于DevicePolicyManagerService之DeviceAdmin的主要内容,如果未能解决你的问题,请参考以下文章