android_frameworks_base/services/java/com/android/server/DevicePolicyManagerService.java
Raj Mamadgi 92d02491ad Fix for the invalid Global Proxy Setting
Adding validation for Global Proxy setting before it is
being set.

Proxy is validated at the boot time also to make sure
the value set is valid.

Signed-off-by: Raj Mamadgi <rmamadgi@sta.samsung.com>
bug:11598568

Change-Id: Idff5ae81119d8143da096b5291ecbfbc5875cbd4
2013-11-14 00:08:21 +00:00

2943 lines
121 KiB
Java

/*
* Copyright (C) 2010 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.server;
import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
import com.android.internal.R;
import com.android.internal.os.storage.ExternalStorageFormatter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.org.conscrypt.TrustedCertificateStore;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import android.app.Activity;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.INotificationManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.net.ProxyProperties;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.IPowerManager;
import android.os.PowerManager;
import android.os.Process;
import android.os.RecoverySystem;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.security.Credentials;
import android.security.IKeyChainService;
import android.security.KeyChain;
import android.security.KeyChain.KeyChainConnection;
import android.util.AtomicFile;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
import android.view.IWindowManager;
import android.view.WindowManagerPolicy;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.KeyStore.TrustedCertificateEntry;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
/**
* Implementation of the device policy APIs.
*/
public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private static final String TAG = "DevicePolicyManagerService";
private static final String DEVICE_POLICIES_XML = "device_policies.xml";
private static final int REQUEST_EXPIRE_PASSWORD = 5571;
private static final long MS_PER_DAY = 86400 * 1000;
private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION
= "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION";
private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
private static final boolean DBG = false;
final Context mContext;
final PowerManager.WakeLock mWakeLock;
IPowerManager mIPowerManager;
IWindowManager mIWindowManager;
NotificationManager mNotificationManager;
private DeviceOwner mDeviceOwner;
/**
* Whether or not device admin feature is supported. If it isn't return defaults for all
* public methods.
*/
private boolean mHasFeature;
public static class DevicePolicyData {
int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
int mActivePasswordLength = 0;
int mActivePasswordUpperCase = 0;
int mActivePasswordLowerCase = 0;
int mActivePasswordLetters = 0;
int mActivePasswordNumeric = 0;
int mActivePasswordSymbols = 0;
int mActivePasswordNonLetter = 0;
int mFailedPasswordAttempts = 0;
int mUserHandle;;
int mPasswordOwner = -1;
long mLastMaximumTimeToLock = -1;
final HashMap<ComponentName, ActiveAdmin> mAdminMap
= new HashMap<ComponentName, ActiveAdmin>();
final ArrayList<ActiveAdmin> mAdminList
= new ArrayList<ActiveAdmin>();
public DevicePolicyData(int userHandle) {
mUserHandle = userHandle;
}
}
final SparseArray<DevicePolicyData> mUserData = new SparseArray<DevicePolicyData>();
Handler mHandler = new Handler();
BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
getSendingUserId());
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|| ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
if (DBG) Slog.v(TAG, "Sending password expiration notifications for action "
+ action + " for user " + userHandle);
mHandler.post(new Runnable() {
public void run() {
handlePasswordExpirationNotification(getUserData(userHandle));
}
});
}
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|| KeyChain.ACTION_STORAGE_CHANGED.equals(action)) {
manageMonitoringCertificateNotification(intent);
}
if (Intent.ACTION_USER_REMOVED.equals(action)) {
removeUserData(userHandle);
} else if (Intent.ACTION_USER_STARTED.equals(action)
|| Intent.ACTION_PACKAGE_CHANGED.equals(action)
|| Intent.ACTION_PACKAGE_REMOVED.equals(action)
|| Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
if (Intent.ACTION_USER_STARTED.equals(action)) {
// Reset the policy data
synchronized (DevicePolicyManagerService.this) {
mUserData.remove(userHandle);
}
}
handlePackagesChanged(userHandle);
}
}
};
static class ActiveAdmin {
final DeviceAdminInfo info;
int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
static final int DEF_MINIMUM_PASSWORD_LENGTH = 0;
int minimumPasswordLength = DEF_MINIMUM_PASSWORD_LENGTH;
static final int DEF_PASSWORD_HISTORY_LENGTH = 0;
int passwordHistoryLength = DEF_PASSWORD_HISTORY_LENGTH;
static final int DEF_MINIMUM_PASSWORD_UPPER_CASE = 0;
int minimumPasswordUpperCase = DEF_MINIMUM_PASSWORD_UPPER_CASE;
static final int DEF_MINIMUM_PASSWORD_LOWER_CASE = 0;
int minimumPasswordLowerCase = DEF_MINIMUM_PASSWORD_LOWER_CASE;
static final int DEF_MINIMUM_PASSWORD_LETTERS = 1;
int minimumPasswordLetters = DEF_MINIMUM_PASSWORD_LETTERS;
static final int DEF_MINIMUM_PASSWORD_NUMERIC = 1;
int minimumPasswordNumeric = DEF_MINIMUM_PASSWORD_NUMERIC;
static final int DEF_MINIMUM_PASSWORD_SYMBOLS = 1;
int minimumPasswordSymbols = DEF_MINIMUM_PASSWORD_SYMBOLS;
static final int DEF_MINIMUM_PASSWORD_NON_LETTER = 0;
int minimumPasswordNonLetter = DEF_MINIMUM_PASSWORD_NON_LETTER;
static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
static final long DEF_PASSWORD_EXPIRATION_TIMEOUT = 0;
long passwordExpirationTimeout = DEF_PASSWORD_EXPIRATION_TIMEOUT;
static final long DEF_PASSWORD_EXPIRATION_DATE = 0;
long passwordExpirationDate = DEF_PASSWORD_EXPIRATION_DATE;
static final int DEF_KEYGUARD_FEATURES_DISABLED = 0; // none
int disabledKeyguardFeatures = DEF_KEYGUARD_FEATURES_DISABLED;
boolean encryptionRequested = false;
boolean disableCamera = false;
// TODO: review implementation decisions with frameworks team
boolean specifiesGlobalProxy = false;
String globalProxySpec = null;
String globalProxyExclusionList = null;
ActiveAdmin(DeviceAdminInfo _info) {
info = _info;
}
int getUid() { return info.getActivityInfo().applicationInfo.uid; }
public UserHandle getUserHandle() {
return new UserHandle(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid));
}
void writeToXml(XmlSerializer out)
throws IllegalArgumentException, IllegalStateException, IOException {
out.startTag(null, "policies");
info.writePoliciesToXml(out);
out.endTag(null, "policies");
if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
out.startTag(null, "password-quality");
out.attribute(null, "value", Integer.toString(passwordQuality));
out.endTag(null, "password-quality");
if (minimumPasswordLength != DEF_MINIMUM_PASSWORD_LENGTH) {
out.startTag(null, "min-password-length");
out.attribute(null, "value", Integer.toString(minimumPasswordLength));
out.endTag(null, "min-password-length");
}
if(passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
out.startTag(null, "password-history-length");
out.attribute(null, "value", Integer.toString(passwordHistoryLength));
out.endTag(null, "password-history-length");
}
if (minimumPasswordUpperCase != DEF_MINIMUM_PASSWORD_UPPER_CASE) {
out.startTag(null, "min-password-uppercase");
out.attribute(null, "value", Integer.toString(minimumPasswordUpperCase));
out.endTag(null, "min-password-uppercase");
}
if (minimumPasswordLowerCase != DEF_MINIMUM_PASSWORD_LOWER_CASE) {
out.startTag(null, "min-password-lowercase");
out.attribute(null, "value", Integer.toString(minimumPasswordLowerCase));
out.endTag(null, "min-password-lowercase");
}
if (minimumPasswordLetters != DEF_MINIMUM_PASSWORD_LETTERS) {
out.startTag(null, "min-password-letters");
out.attribute(null, "value", Integer.toString(minimumPasswordLetters));
out.endTag(null, "min-password-letters");
}
if (minimumPasswordNumeric != DEF_MINIMUM_PASSWORD_NUMERIC) {
out.startTag(null, "min-password-numeric");
out.attribute(null, "value", Integer.toString(minimumPasswordNumeric));
out.endTag(null, "min-password-numeric");
}
if (minimumPasswordSymbols != DEF_MINIMUM_PASSWORD_SYMBOLS) {
out.startTag(null, "min-password-symbols");
out.attribute(null, "value", Integer.toString(minimumPasswordSymbols));
out.endTag(null, "min-password-symbols");
}
if (minimumPasswordNonLetter > DEF_MINIMUM_PASSWORD_NON_LETTER) {
out.startTag(null, "min-password-nonletter");
out.attribute(null, "value", Integer.toString(minimumPasswordNonLetter));
out.endTag(null, "min-password-nonletter");
}
}
if (maximumTimeToUnlock != DEF_MAXIMUM_TIME_TO_UNLOCK) {
out.startTag(null, "max-time-to-unlock");
out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
out.endTag(null, "max-time-to-unlock");
}
if (maximumFailedPasswordsForWipe != DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE) {
out.startTag(null, "max-failed-password-wipe");
out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
out.endTag(null, "max-failed-password-wipe");
}
if (specifiesGlobalProxy) {
out.startTag(null, "specifies-global-proxy");
out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
out.endTag(null, "specifies_global_proxy");
if (globalProxySpec != null) {
out.startTag(null, "global-proxy-spec");
out.attribute(null, "value", globalProxySpec);
out.endTag(null, "global-proxy-spec");
}
if (globalProxyExclusionList != null) {
out.startTag(null, "global-proxy-exclusion-list");
out.attribute(null, "value", globalProxyExclusionList);
out.endTag(null, "global-proxy-exclusion-list");
}
}
if (passwordExpirationTimeout != DEF_PASSWORD_EXPIRATION_TIMEOUT) {
out.startTag(null, "password-expiration-timeout");
out.attribute(null, "value", Long.toString(passwordExpirationTimeout));
out.endTag(null, "password-expiration-timeout");
}
if (passwordExpirationDate != DEF_PASSWORD_EXPIRATION_DATE) {
out.startTag(null, "password-expiration-date");
out.attribute(null, "value", Long.toString(passwordExpirationDate));
out.endTag(null, "password-expiration-date");
}
if (encryptionRequested) {
out.startTag(null, "encryption-requested");
out.attribute(null, "value", Boolean.toString(encryptionRequested));
out.endTag(null, "encryption-requested");
}
if (disableCamera) {
out.startTag(null, "disable-camera");
out.attribute(null, "value", Boolean.toString(disableCamera));
out.endTag(null, "disable-camera");
}
if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
out.startTag(null, "disable-keyguard-features");
out.attribute(null, "value", Integer.toString(disabledKeyguardFeatures));
out.endTag(null, "disable-keyguard-features");
}
}
void readFromXml(XmlPullParser parser)
throws XmlPullParserException, IOException {
int outerDepth = parser.getDepth();
int type;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tag = parser.getName();
if ("policies".equals(tag)) {
info.readPoliciesFromXml(parser);
} else if ("password-quality".equals(tag)) {
passwordQuality = Integer.parseInt(
parser.getAttributeValue(null, "value"));
} else if ("min-password-length".equals(tag)) {
minimumPasswordLength = Integer.parseInt(
parser.getAttributeValue(null, "value"));
} else if ("password-history-length".equals(tag)) {
passwordHistoryLength = Integer.parseInt(
parser.getAttributeValue(null, "value"));
} else if ("min-password-uppercase".equals(tag)) {
minimumPasswordUpperCase = Integer.parseInt(
parser.getAttributeValue(null, "value"));
} else if ("min-password-lowercase".equals(tag)) {
minimumPasswordLowerCase = Integer.parseInt(
parser.getAttributeValue(null, "value"));
} else if ("min-password-letters".equals(tag)) {
minimumPasswordLetters = Integer.parseInt(
parser.getAttributeValue(null, "value"));
} else if ("min-password-numeric".equals(tag)) {
minimumPasswordNumeric = Integer.parseInt(
parser.getAttributeValue(null, "value"));
} else if ("min-password-symbols".equals(tag)) {
minimumPasswordSymbols = Integer.parseInt(
parser.getAttributeValue(null, "value"));
} else if ("min-password-nonletter".equals(tag)) {
minimumPasswordNonLetter = Integer.parseInt(
parser.getAttributeValue(null, "value"));
} else if ("max-time-to-unlock".equals(tag)) {
maximumTimeToUnlock = Long.parseLong(
parser.getAttributeValue(null, "value"));
} else if ("max-failed-password-wipe".equals(tag)) {
maximumFailedPasswordsForWipe = Integer.parseInt(
parser.getAttributeValue(null, "value"));
} else if ("specifies-global-proxy".equals(tag)) {
specifiesGlobalProxy = Boolean.parseBoolean(
parser.getAttributeValue(null, "value"));
} else if ("global-proxy-spec".equals(tag)) {
globalProxySpec =
parser.getAttributeValue(null, "value");
} else if ("global-proxy-exclusion-list".equals(tag)) {
globalProxyExclusionList =
parser.getAttributeValue(null, "value");
} else if ("password-expiration-timeout".equals(tag)) {
passwordExpirationTimeout = Long.parseLong(
parser.getAttributeValue(null, "value"));
} else if ("password-expiration-date".equals(tag)) {
passwordExpirationDate = Long.parseLong(
parser.getAttributeValue(null, "value"));
} else if ("encryption-requested".equals(tag)) {
encryptionRequested = Boolean.parseBoolean(
parser.getAttributeValue(null, "value"));
} else if ("disable-camera".equals(tag)) {
disableCamera = Boolean.parseBoolean(
parser.getAttributeValue(null, "value"));
} else if ("disable-keyguard-features".equals(tag)) {
disabledKeyguardFeatures = Integer.parseInt(
parser.getAttributeValue(null, "value"));
} else {
Slog.w(TAG, "Unknown admin tag: " + tag);
}
XmlUtils.skipCurrentTag(parser);
}
}
void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("uid="); pw.println(getUid());
pw.print(prefix); pw.println("policies:");
ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
if (pols != null) {
for (int i=0; i<pols.size(); i++) {
pw.print(prefix); pw.print(" "); pw.println(pols.get(i).tag);
}
}
pw.print(prefix); pw.print("passwordQuality=0x");
pw.println(Integer.toHexString(passwordQuality));
pw.print(prefix); pw.print("minimumPasswordLength=");
pw.println(minimumPasswordLength);
pw.print(prefix); pw.print("passwordHistoryLength=");
pw.println(passwordHistoryLength);
pw.print(prefix); pw.print("minimumPasswordUpperCase=");
pw.println(minimumPasswordUpperCase);
pw.print(prefix); pw.print("minimumPasswordLowerCase=");
pw.println(minimumPasswordLowerCase);
pw.print(prefix); pw.print("minimumPasswordLetters=");
pw.println(minimumPasswordLetters);
pw.print(prefix); pw.print("minimumPasswordNumeric=");
pw.println(minimumPasswordNumeric);
pw.print(prefix); pw.print("minimumPasswordSymbols=");
pw.println(minimumPasswordSymbols);
pw.print(prefix); pw.print("minimumPasswordNonLetter=");
pw.println(minimumPasswordNonLetter);
pw.print(prefix); pw.print("maximumTimeToUnlock=");
pw.println(maximumTimeToUnlock);
pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
pw.println(maximumFailedPasswordsForWipe);
pw.print(prefix); pw.print("specifiesGlobalProxy=");
pw.println(specifiesGlobalProxy);
pw.print(prefix); pw.print("passwordExpirationTimeout=");
pw.println(passwordExpirationTimeout);
pw.print(prefix); pw.print("passwordExpirationDate=");
pw.println(passwordExpirationDate);
if (globalProxySpec != null) {
pw.print(prefix); pw.print("globalProxySpec=");
pw.println(globalProxySpec);
}
if (globalProxyExclusionList != null) {
pw.print(prefix); pw.print("globalProxyEclusionList=");
pw.println(globalProxyExclusionList);
}
pw.print(prefix); pw.print("encryptionRequested=");
pw.println(encryptionRequested);
pw.print(prefix); pw.print("disableCamera=");
pw.println(disableCamera);
pw.print(prefix); pw.print("disabledKeyguardFeatures=");
pw.println(disabledKeyguardFeatures);
}
}
private void handlePackagesChanged(int userHandle) {
boolean removed = false;
if (DBG) Slog.d(TAG, "Handling package changes for user " + userHandle);
DevicePolicyData policy = getUserData(userHandle);
IPackageManager pm = AppGlobals.getPackageManager();
for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
ActiveAdmin aa = policy.mAdminList.get(i);
try {
if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null
|| pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) {
removed = true;
policy.mAdminList.remove(i);
policy.mAdminMap.remove(aa.info.getComponent());
}
} catch (RemoteException re) {
// Shouldn't happen
}
}
if (removed) {
validatePasswordOwnerLocked(policy);
syncDeviceCapabilitiesLocked(policy);
saveSettingsLocked(policy.mUserHandle);
}
}
/**
* Instantiates the service.
*/
public DevicePolicyManagerService(Context context) {
mContext = context;
mHasFeature = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_DEVICE_ADMIN);
mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE))
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
if (!mHasFeature) {
// Skip the rest of the initialization
return;
}
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION);
filter.addAction(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_STARTED);
filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addDataScheme("package");
context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
}
/**
* Creates and loads the policy data from xml.
* @param userHandle the user for whom to load the policy data
* @return
*/
DevicePolicyData getUserData(int userHandle) {
synchronized (this) {
DevicePolicyData policy = mUserData.get(userHandle);
if (policy == null) {
policy = new DevicePolicyData(userHandle);
mUserData.append(userHandle, policy);
loadSettingsLocked(policy, userHandle);
}
return policy;
}
}
void removeUserData(int userHandle) {
synchronized (this) {
if (userHandle == UserHandle.USER_OWNER) {
Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring.");
return;
}
DevicePolicyData policy = mUserData.get(userHandle);
if (policy != null) {
mUserData.remove(userHandle);
}
File policyFile = new File(Environment.getUserSystemDirectory(userHandle),
DEVICE_POLICIES_XML);
policyFile.delete();
Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath());
}
}
void loadDeviceOwner() {
synchronized (this) {
if (DeviceOwner.isRegistered()) {
mDeviceOwner = new DeviceOwner();
}
}
}
/**
* Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
* reminders. Clears alarm if no expirations are configured.
*/
protected void setExpirationAlarmCheckLocked(Context context, DevicePolicyData policy) {
final long expiration = getPasswordExpirationLocked(null, policy.mUserHandle);
final long now = System.currentTimeMillis();
final long timeToExpire = expiration - now;
final long alarmTime;
if (expiration == 0) {
// No expirations are currently configured: Cancel alarm.
alarmTime = 0;
} else if (timeToExpire <= 0) {
// The password has already expired: Repeat every 24 hours.
alarmTime = now + MS_PER_DAY;
} else {
// Selecting the next alarm time: Roll forward to the next 24 hour multiple before
// the expiration time.
long alarmInterval = timeToExpire % MS_PER_DAY;
if (alarmInterval == 0) {
alarmInterval = MS_PER_DAY;
}
alarmTime = now + alarmInterval;
}
long token = Binder.clearCallingIdentity();
try {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT,
new UserHandle(policy.mUserHandle));
am.cancel(pi);
if (alarmTime != 0) {
am.set(AlarmManager.RTC, alarmTime, pi);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
private IPowerManager getIPowerManager() {
if (mIPowerManager == null) {
IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
mIPowerManager = IPowerManager.Stub.asInterface(b);
}
return mIPowerManager;
}
private IWindowManager getWindowManager() {
if (mIWindowManager == null) {
IBinder b = ServiceManager.getService(Context.WINDOW_SERVICE);
mIWindowManager = IWindowManager.Stub.asInterface(b);
}
return mIWindowManager;
}
private NotificationManager getNotificationManager() {
if (mNotificationManager == null) {
mNotificationManager =
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
}
return mNotificationManager;
}
ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) {
ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who);
if (admin != null
&& who.getPackageName().equals(admin.info.getActivityInfo().packageName)
&& who.getClassName().equals(admin.info.getActivityInfo().name)) {
return admin;
}
return null;
}
ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
throws SecurityException {
final int callingUid = Binder.getCallingUid();
final int userHandle = UserHandle.getUserId(callingUid);
final DevicePolicyData policy = getUserData(userHandle);
if (who != null) {
ActiveAdmin admin = policy.mAdminMap.get(who);
if (admin == null) {
throw new SecurityException("No active admin " + who);
}
if (admin.getUid() != callingUid) {
throw new SecurityException("Admin " + who + " is not owned by uid "
+ Binder.getCallingUid());
}
if (!admin.info.usesPolicy(reqPolicy)) {
throw new SecurityException("Admin " + admin.info.getComponent()
+ " did not specify uses-policy for: "
+ admin.info.getTagForPolicy(reqPolicy));
}
return admin;
} else {
final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
return admin;
}
}
throw new SecurityException("No active admin owned by uid "
+ Binder.getCallingUid() + " for policy #" + reqPolicy);
}
}
void sendAdminCommandLocked(ActiveAdmin admin, String action) {
sendAdminCommandLocked(admin, action, null);
}
void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) {
Intent intent = new Intent(action);
intent.setComponent(admin.info.getComponent());
if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
intent.putExtra("expiration", admin.passwordExpirationDate);
}
if (result != null) {
mContext.sendOrderedBroadcastAsUser(intent, admin.getUserHandle(),
null, result, mHandler, Activity.RESULT_OK, null, null);
} else {
mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
}
}
void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) {
final DevicePolicyData policy = getUserData(userHandle);
final int count = policy.mAdminList.size();
if (count > 0) {
for (int i = 0; i < count; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (admin.info.usesPolicy(reqPolicy)) {
sendAdminCommandLocked(admin, action);
}
}
}
}
void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) {
final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
if (admin != null) {
sendAdminCommandLocked(admin,
DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
synchronized (DevicePolicyManagerService.this) {
int userHandle = admin.getUserHandle().getIdentifier();
DevicePolicyData policy = getUserData(userHandle);
boolean doProxyCleanup = admin.info.usesPolicy(
DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
policy.mAdminList.remove(admin);
policy.mAdminMap.remove(adminReceiver);
validatePasswordOwnerLocked(policy);
syncDeviceCapabilitiesLocked(policy);
if (doProxyCleanup) {
resetGlobalProxyLocked(getUserData(userHandle));
}
saveSettingsLocked(userHandle);
updateMaximumTimeToLockLocked(policy);
}
}
});
}
}
public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) {
if (!mHasFeature) {
return null;
}
enforceCrossUserPermission(userHandle);
Intent resolveIntent = new Intent();
resolveIntent.setComponent(adminName);
List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
resolveIntent,
PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
userHandle);
if (infos == null || infos.size() <= 0) {
throw new IllegalArgumentException("Unknown admin: " + adminName);
}
try {
return new DeviceAdminInfo(mContext, infos.get(0));
} catch (XmlPullParserException e) {
Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
return null;
} catch (IOException e) {
Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e);
return null;
}
}
private static JournaledFile makeJournaledFile(int userHandle) {
final String base = userHandle == 0
? "/data/system/" + DEVICE_POLICIES_XML
: new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML)
.getAbsolutePath();
return new JournaledFile(new File(base), new File(base + ".tmp"));
}
private void saveSettingsLocked(int userHandle) {
DevicePolicyData policy = getUserData(userHandle);
JournaledFile journal = makeJournaledFile(userHandle);
FileOutputStream stream = null;
try {
stream = new FileOutputStream(journal.chooseForWrite(), false);
XmlSerializer out = new FastXmlSerializer();
out.setOutput(stream, "utf-8");
out.startDocument(null, true);
out.startTag(null, "policies");
final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin ap = policy.mAdminList.get(i);
if (ap != null) {
out.startTag(null, "admin");
out.attribute(null, "name", ap.info.getComponent().flattenToString());
ap.writeToXml(out);
out.endTag(null, "admin");
}
}
if (policy.mPasswordOwner >= 0) {
out.startTag(null, "password-owner");
out.attribute(null, "value", Integer.toString(policy.mPasswordOwner));
out.endTag(null, "password-owner");
}
if (policy.mFailedPasswordAttempts != 0) {
out.startTag(null, "failed-password-attempts");
out.attribute(null, "value", Integer.toString(policy.mFailedPasswordAttempts));
out.endTag(null, "failed-password-attempts");
}
if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0
|| policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0
|| policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0
|| policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) {
out.startTag(null, "active-password");
out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality));
out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength));
out.attribute(null, "uppercase", Integer.toString(policy.mActivePasswordUpperCase));
out.attribute(null, "lowercase", Integer.toString(policy.mActivePasswordLowerCase));
out.attribute(null, "letters", Integer.toString(policy.mActivePasswordLetters));
out.attribute(null, "numeric", Integer
.toString(policy.mActivePasswordNumeric));
out.attribute(null, "symbols", Integer.toString(policy.mActivePasswordSymbols));
out.attribute(null, "nonletter", Integer.toString(policy.mActivePasswordNonLetter));
out.endTag(null, "active-password");
}
out.endTag(null, "policies");
out.endDocument();
stream.close();
journal.commit();
sendChangedNotification(userHandle);
} catch (IOException e) {
try {
if (stream != null) {
stream.close();
}
} catch (IOException ex) {
// Ignore
}
journal.rollback();
}
}
private void sendChangedNotification(int userHandle) {
Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
long ident = Binder.clearCallingIdentity();
try {
mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void loadSettingsLocked(DevicePolicyData policy, int userHandle) {
JournaledFile journal = makeJournaledFile(userHandle);
FileInputStream stream = null;
File file = journal.chooseForRead();
try {
stream = new FileInputStream(file);
XmlPullParser parser = Xml.newPullParser();
parser.setInput(stream, null);
int type;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& type != XmlPullParser.START_TAG) {
}
String tag = parser.getName();
if (!"policies".equals(tag)) {
throw new XmlPullParserException(
"Settings do not start with policies tag: found " + tag);
}
type = parser.next();
int outerDepth = parser.getDepth();
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
tag = parser.getName();
if ("admin".equals(tag)) {
String name = parser.getAttributeValue(null, "name");
try {
DeviceAdminInfo dai = findAdmin(
ComponentName.unflattenFromString(name), userHandle);
if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
!= userHandle)) {
Slog.w(TAG, "findAdmin returned an incorrect uid "
+ dai.getActivityInfo().applicationInfo.uid + " for user "
+ userHandle);
}
if (dai != null) {
ActiveAdmin ap = new ActiveAdmin(dai);
ap.readFromXml(parser);
policy.mAdminMap.put(ap.info.getComponent(), ap);
policy.mAdminList.add(ap);
}
} catch (RuntimeException e) {
Slog.w(TAG, "Failed loading admin " + name, e);
}
} else if ("failed-password-attempts".equals(tag)) {
policy.mFailedPasswordAttempts = Integer.parseInt(
parser.getAttributeValue(null, "value"));
XmlUtils.skipCurrentTag(parser);
} else if ("password-owner".equals(tag)) {
policy.mPasswordOwner = Integer.parseInt(
parser.getAttributeValue(null, "value"));
XmlUtils.skipCurrentTag(parser);
} else if ("active-password".equals(tag)) {
policy.mActivePasswordQuality = Integer.parseInt(
parser.getAttributeValue(null, "quality"));
policy.mActivePasswordLength = Integer.parseInt(
parser.getAttributeValue(null, "length"));
policy.mActivePasswordUpperCase = Integer.parseInt(
parser.getAttributeValue(null, "uppercase"));
policy.mActivePasswordLowerCase = Integer.parseInt(
parser.getAttributeValue(null, "lowercase"));
policy.mActivePasswordLetters = Integer.parseInt(
parser.getAttributeValue(null, "letters"));
policy.mActivePasswordNumeric = Integer.parseInt(
parser.getAttributeValue(null, "numeric"));
policy.mActivePasswordSymbols = Integer.parseInt(
parser.getAttributeValue(null, "symbols"));
policy.mActivePasswordNonLetter = Integer.parseInt(
parser.getAttributeValue(null, "nonletter"));
XmlUtils.skipCurrentTag(parser);
} else {
Slog.w(TAG, "Unknown tag: " + tag);
XmlUtils.skipCurrentTag(parser);
}
}
} catch (NullPointerException e) {
Slog.w(TAG, "failed parsing " + file + " " + e);
} catch (NumberFormatException e) {
Slog.w(TAG, "failed parsing " + file + " " + e);
} catch (XmlPullParserException e) {
Slog.w(TAG, "failed parsing " + file + " " + e);
} catch (FileNotFoundException e) {
// Don't be noisy, this is normal if we haven't defined any policies.
} catch (IOException e) {
Slog.w(TAG, "failed parsing " + file + " " + e);
} catch (IndexOutOfBoundsException e) {
Slog.w(TAG, "failed parsing " + file + " " + e);
}
try {
if (stream != null) {
stream.close();
}
} catch (IOException e) {
// Ignore
}
// Validate that what we stored for the password quality matches
// sufficiently what is currently set. Note that this is only
// a sanity check in case the two get out of sync; this should
// never normally happen.
LockPatternUtils utils = new LockPatternUtils(mContext);
if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) {
Slog.w(TAG, "Active password quality 0x"
+ Integer.toHexString(policy.mActivePasswordQuality)
+ " does not match actual quality 0x"
+ Integer.toHexString(utils.getActivePasswordQuality()));
policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
policy.mActivePasswordLength = 0;
policy.mActivePasswordUpperCase = 0;
policy.mActivePasswordLowerCase = 0;
policy.mActivePasswordLetters = 0;
policy.mActivePasswordNumeric = 0;
policy.mActivePasswordSymbols = 0;
policy.mActivePasswordNonLetter = 0;
}
validatePasswordOwnerLocked(policy);
syncDeviceCapabilitiesLocked(policy);
updateMaximumTimeToLockLocked(policy);
}
static void validateQualityConstant(int quality) {
switch (quality) {
case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
case DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK:
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
return;
}
throw new IllegalArgumentException("Invalid quality constant: 0x"
+ Integer.toHexString(quality));
}
void validatePasswordOwnerLocked(DevicePolicyData policy) {
if (policy.mPasswordOwner >= 0) {
boolean haveOwner = false;
for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
if (policy.mAdminList.get(i).getUid() == policy.mPasswordOwner) {
haveOwner = true;
break;
}
}
if (!haveOwner) {
Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner
+ " no longer active; disabling");
policy.mPasswordOwner = -1;
}
}
}
/**
* Pushes down policy information to the system for any policies related to general device
* capabilities that need to be enforced by lower level services (e.g. Camera services).
*/
void syncDeviceCapabilitiesLocked(DevicePolicyData policy) {
// Ensure the status of the camera is synced down to the system. Interested native services
// should monitor this value and act accordingly.
boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false);
boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle);
if (cameraDisabled != systemState) {
long token = Binder.clearCallingIdentity();
try {
String value = cameraDisabled ? "1" : "0";
if (DBG) Slog.v(TAG, "Change in camera state ["
+ SYSTEM_PROP_DISABLE_CAMERA + "] = " + value);
SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value);
} finally {
Binder.restoreCallingIdentity(token);
}
}
}
public void systemReady() {
if (!mHasFeature) {
return;
}
synchronized (this) {
loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER);
loadDeviceOwner();
}
}
private void handlePasswordExpirationNotification(DevicePolicyData policy) {
synchronized (this) {
final long now = System.currentTimeMillis();
final int N = policy.mAdminList.size();
if (N <= 0) {
return;
}
for (int i=0; i < N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
&& admin.passwordExpirationTimeout > 0L
&& admin.passwordExpirationDate > 0L
&& now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
}
}
setExpirationAlarmCheckLocked(mContext, policy);
}
}
private void manageMonitoringCertificateNotification(Intent intent) {
final NotificationManager notificationManager = getNotificationManager();
final boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled();
if (! hasCert) {
if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
for (UserInfo user : um.getUsers()) {
notificationManager.cancelAsUser(
null, MONITORING_CERT_NOTIFICATION_ID, user.getUserHandle());
}
}
return;
}
final boolean isManaged = getDeviceOwner() != null;
int smallIconId;
String contentText;
if (isManaged) {
contentText = mContext.getString(R.string.ssl_ca_cert_noti_managed,
getDeviceOwnerName());
smallIconId = R.drawable.stat_sys_certificate_info;
} else {
contentText = mContext.getString(R.string.ssl_ca_cert_noti_by_unknown);
smallIconId = android.R.drawable.stat_sys_warning;
}
Intent dialogIntent = new Intent(Settings.ACTION_MONITORING_CERT_INFO);
dialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
dialogIntent.setPackage("com.android.settings");
// Notification will be sent individually to all users. The activity should start as
// whichever user is current when it starts.
PendingIntent notifyIntent = PendingIntent.getActivityAsUser(mContext, 0, dialogIntent,
PendingIntent.FLAG_UPDATE_CURRENT, null, UserHandle.CURRENT);
Notification noti = new Notification.Builder(mContext)
.setSmallIcon(smallIconId)
.setContentTitle(mContext.getString(R.string.ssl_ca_cert_warning))
.setContentText(contentText)
.setContentIntent(notifyIntent)
.setPriority(Notification.PRIORITY_HIGH)
.setShowWhen(false)
.build();
// If this is a boot intent, this will fire for each user. But if this is a storage changed
// intent, it will fire once, so we need to notify all users.
if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
for (UserInfo user : um.getUsers()) {
notificationManager.notifyAsUser(
null, MONITORING_CERT_NOTIFICATION_ID, noti, user.getUserHandle());
}
} else {
notificationManager.notifyAsUser(
null, MONITORING_CERT_NOTIFICATION_ID, noti, UserHandle.CURRENT);
}
}
/**
* @param adminReceiver The admin to add
* @param refreshing true = update an active admin, no error
*/
public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) {
if (!mHasFeature) {
return;
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
enforceCrossUserPermission(userHandle);
DevicePolicyData policy = getUserData(userHandle);
DeviceAdminInfo info = findAdmin(adminReceiver, userHandle);
if (info == null) {
throw new IllegalArgumentException("Bad admin: " + adminReceiver);
}
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
throw new IllegalArgumentException("Admin is already added");
}
ActiveAdmin newAdmin = new ActiveAdmin(info);
policy.mAdminMap.put(adminReceiver, newAdmin);
int replaceIndex = -1;
if (refreshing) {
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);
} else {
policy.mAdminList.set(replaceIndex, newAdmin);
}
saveSettingsLocked(userHandle);
sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
public boolean isAdminActive(ComponentName adminReceiver, int userHandle) {
if (!mHasFeature) {
return false;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null;
}
}
public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) {
if (!mHasFeature) {
return false;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
if (administrator == null) {
throw new SecurityException("No active admin " + adminReceiver);
}
return administrator.info.usesPolicy(policyId);
}
}
@SuppressWarnings("unchecked")
public List<ComponentName> getActiveAdmins(int userHandle) {
if (!mHasFeature) {
return Collections.EMPTY_LIST;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
if (N <= 0) {
return null;
}
ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
for (int i=0; i<N; i++) {
res.add(policy.mAdminList.get(i).info.getComponent());
}
return res;
}
}
public boolean packageHasActiveAdmins(String packageName, int userHandle) {
if (!mHasFeature) {
return false;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
if (policy.mAdminList.get(i).info.getPackageName().equals(packageName)) {
return true;
}
}
return false;
}
}
public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) {
if (!mHasFeature) {
return;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle);
if (admin == null) {
return;
}
if (admin.getUid() != Binder.getCallingUid()) {
// If trying to remove device owner, refuse when the caller is not the owner.
if (mDeviceOwner != null
&& adminReceiver.getPackageName().equals(mDeviceOwner.getPackageName())) {
return;
}
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
}
long ident = Binder.clearCallingIdentity();
try {
removeActiveAdminLocked(adminReceiver, userHandle);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
public void setPasswordQuality(ComponentName who, int quality, int userHandle) {
if (!mHasFeature) {
return;
}
validateQualityConstant(quality);
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.passwordQuality != quality) {
ap.passwordQuality = quality;
saveSettingsLocked(userHandle);
}
}
}
public int getPasswordQuality(ComponentName who, int userHandle) {
if (!mHasFeature) {
return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
DevicePolicyData policy = getUserData(userHandle);
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.passwordQuality : mode;
}
final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (mode < admin.passwordQuality) {
mode = admin.passwordQuality;
}
}
return mode;
}
}
public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) {
if (!mHasFeature) {
return;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.minimumPasswordLength != length) {
ap.minimumPasswordLength = length;
saveSettingsLocked(userHandle);
}
}
}
public int getPasswordMinimumLength(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
int length = 0;
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.minimumPasswordLength : length;
}
final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (length < admin.minimumPasswordLength) {
length = admin.minimumPasswordLength;
}
}
return length;
}
}
public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) {
if (!mHasFeature) {
return;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.passwordHistoryLength != length) {
ap.passwordHistoryLength = length;
saveSettingsLocked(userHandle);
}
}
}
public int getPasswordHistoryLength(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
int length = 0;
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.passwordHistoryLength : length;
}
final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (length < admin.passwordHistoryLength) {
length = admin.passwordHistoryLength;
}
}
return length;
}
}
public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) {
if (!mHasFeature) {
return;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
if (timeout < 0) {
throw new IllegalArgumentException("Timeout must be >= 0 ms");
}
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
// Calling this API automatically bumps the expiration date
final long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
ap.passwordExpirationDate = expiration;
ap.passwordExpirationTimeout = timeout;
if (timeout > 0L) {
Slog.w(TAG, "setPasswordExpiration(): password will expire on "
+ DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)
.format(new Date(expiration)));
}
saveSettingsLocked(userHandle);
// in case this is the first one
setExpirationAlarmCheckLocked(mContext, getUserData(userHandle));
}
}
/**
* Return a single admin's expiration cycle time, or the min of all cycle times.
* Returns 0 if not configured.
*/
public long getPasswordExpirationTimeout(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0L;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.passwordExpirationTimeout : 0L;
}
long timeout = 0L;
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (timeout == 0L || (admin.passwordExpirationTimeout != 0L
&& timeout > admin.passwordExpirationTimeout)) {
timeout = admin.passwordExpirationTimeout;
}
}
return timeout;
}
}
/**
* Return a single admin's expiration date/time, or the min (soonest) for all admins.
* Returns 0 if not configured.
*/
private long getPasswordExpirationLocked(ComponentName who, int userHandle) {
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.passwordExpirationDate : 0L;
}
long timeout = 0L;
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (timeout == 0L || (admin.passwordExpirationDate != 0
&& timeout > admin.passwordExpirationDate)) {
timeout = admin.passwordExpirationDate;
}
}
return timeout;
}
public long getPasswordExpiration(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0L;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
return getPasswordExpirationLocked(who, userHandle);
}
}
public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) {
if (!mHasFeature) {
return;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.minimumPasswordUpperCase != length) {
ap.minimumPasswordUpperCase = length;
saveSettingsLocked(userHandle);
}
}
}
public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.minimumPasswordUpperCase : length;
}
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (length < admin.minimumPasswordUpperCase) {
length = admin.minimumPasswordUpperCase;
}
}
return length;
}
}
public void setPasswordMinimumLowerCase(ComponentName who, int length, int userHandle) {
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.minimumPasswordLowerCase != length) {
ap.minimumPasswordLowerCase = length;
saveSettingsLocked(userHandle);
}
}
}
public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.minimumPasswordLowerCase : length;
}
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (length < admin.minimumPasswordLowerCase) {
length = admin.minimumPasswordLowerCase;
}
}
return length;
}
}
public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) {
if (!mHasFeature) {
return;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.minimumPasswordLetters != length) {
ap.minimumPasswordLetters = length;
saveSettingsLocked(userHandle);
}
}
}
public int getPasswordMinimumLetters(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.minimumPasswordLetters : length;
}
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (length < admin.minimumPasswordLetters) {
length = admin.minimumPasswordLetters;
}
}
return length;
}
}
public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) {
if (!mHasFeature) {
return;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.minimumPasswordNumeric != length) {
ap.minimumPasswordNumeric = length;
saveSettingsLocked(userHandle);
}
}
}
public int getPasswordMinimumNumeric(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.minimumPasswordNumeric : length;
}
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (length < admin.minimumPasswordNumeric) {
length = admin.minimumPasswordNumeric;
}
}
return length;
}
}
public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) {
if (!mHasFeature) {
return;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.minimumPasswordSymbols != length) {
ap.minimumPasswordSymbols = length;
saveSettingsLocked(userHandle);
}
}
}
public int getPasswordMinimumSymbols(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.minimumPasswordSymbols : length;
}
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (length < admin.minimumPasswordSymbols) {
length = admin.minimumPasswordSymbols;
}
}
return length;
}
}
public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) {
if (!mHasFeature) {
return;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (ap.minimumPasswordNonLetter != length) {
ap.minimumPasswordNonLetter = length;
saveSettingsLocked(userHandle);
}
}
}
public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
int length = 0;
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.minimumPasswordNonLetter : length;
}
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (length < admin.minimumPasswordNonLetter) {
length = admin.minimumPasswordNonLetter;
}
}
return length;
}
}
public boolean isActivePasswordSufficient(int userHandle) {
if (!mHasFeature) {
return true;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
getActiveAdminForCallerLocked(null,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle)
|| policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
return false;
}
if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
return true;
}
return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle)
&& policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle)
&& policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle)
&& policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle)
&& policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle)
&& policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle);
}
}
public int getCurrentFailedPasswordAttempts(int userHandle) {
enforceCrossUserPermission(userHandle);
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
getActiveAdminForCallerLocked(null,
DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
return getUserData(userHandle).mFailedPasswordAttempts;
}
}
public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) {
if (!mHasFeature) {
return;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_WIPE_DATA);
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
if (ap.maximumFailedPasswordsForWipe != num) {
ap.maximumFailedPasswordsForWipe = num;
saveSettingsLocked(userHandle);
}
}
}
public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
int count = 0;
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.maximumFailedPasswordsForWipe : count;
}
final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (count == 0) {
count = admin.maximumFailedPasswordsForWipe;
} else if (admin.maximumFailedPasswordsForWipe != 0
&& count > admin.maximumFailedPasswordsForWipe) {
count = admin.maximumFailedPasswordsForWipe;
}
}
return count;
}
}
public boolean resetPassword(String password, int flags, int userHandle) {
if (!mHasFeature) {
return false;
}
enforceCrossUserPermission(userHandle);
int quality;
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
getActiveAdminForCallerLocked(null,
DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
quality = getPasswordQuality(null, userHandle);
if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
int realQuality = LockPatternUtils.computePasswordQuality(password);
if (realQuality < quality
&& quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
Slog.w(TAG, "resetPassword: password quality 0x"
+ Integer.toHexString(realQuality)
+ " does not meet required quality 0x"
+ Integer.toHexString(quality));
return false;
}
quality = Math.max(realQuality, quality);
}
int length = getPasswordMinimumLength(null, userHandle);
if (password.length() < length) {
Slog.w(TAG, "resetPassword: password length " + password.length()
+ " does not meet required length " + length);
return false;
}
if (quality == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) {
int letters = 0;
int uppercase = 0;
int lowercase = 0;
int numbers = 0;
int symbols = 0;
int nonletter = 0;
for (int i = 0; i < password.length(); i++) {
char c = password.charAt(i);
if (c >= 'A' && c <= 'Z') {
letters++;
uppercase++;
} else if (c >= 'a' && c <= 'z') {
letters++;
lowercase++;
} else if (c >= '0' && c <= '9') {
numbers++;
nonletter++;
} else {
symbols++;
nonletter++;
}
}
int neededLetters = getPasswordMinimumLetters(null, userHandle);
if(letters < neededLetters) {
Slog.w(TAG, "resetPassword: number of letters " + letters
+ " does not meet required number of letters " + neededLetters);
return false;
}
int neededNumbers = getPasswordMinimumNumeric(null, userHandle);
if (numbers < neededNumbers) {
Slog.w(TAG, "resetPassword: number of numerical digits " + numbers
+ " does not meet required number of numerical digits "
+ neededNumbers);
return false;
}
int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle);
if (lowercase < neededLowerCase) {
Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase
+ " does not meet required number of lowercase letters "
+ neededLowerCase);
return false;
}
int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle);
if (uppercase < neededUpperCase) {
Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase
+ " does not meet required number of uppercase letters "
+ neededUpperCase);
return false;
}
int neededSymbols = getPasswordMinimumSymbols(null, userHandle);
if (symbols < neededSymbols) {
Slog.w(TAG, "resetPassword: number of special symbols " + symbols
+ " does not meet required number of special symbols " + neededSymbols);
return false;
}
int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle);
if (nonletter < neededNonLetter) {
Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter
+ " does not meet required number of non-letter characters "
+ neededNonLetter);
return false;
}
}
}
int callingUid = Binder.getCallingUid();
DevicePolicyData policy = getUserData(userHandle);
if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
return false;
}
// Don't do this with the lock held, because it is going to call
// back in to the service.
long ident = Binder.clearCallingIdentity();
try {
LockPatternUtils utils = new LockPatternUtils(mContext);
utils.saveLockPassword(password, quality, false, userHandle);
synchronized (this) {
int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
!= 0 ? callingUid : -1;
if (policy.mPasswordOwner != newOwner) {
policy.mPasswordOwner = newOwner;
saveSettingsLocked(userHandle);
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
return true;
}
public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) {
if (!mHasFeature) {
return;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
if (ap.maximumTimeToUnlock != timeMs) {
ap.maximumTimeToUnlock = timeMs;
saveSettingsLocked(userHandle);
updateMaximumTimeToLockLocked(getUserData(userHandle));
}
}
}
void updateMaximumTimeToLockLocked(DevicePolicyData policy) {
long timeMs = getMaximumTimeToLock(null, policy.mUserHandle);
if (policy.mLastMaximumTimeToLock == timeMs) {
return;
}
long ident = Binder.clearCallingIdentity();
try {
if (timeMs <= 0) {
timeMs = Integer.MAX_VALUE;
} else {
// Make sure KEEP_SCREEN_ON is disabled, since that
// would allow bypassing of the maximum time to lock.
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
}
policy.mLastMaximumTimeToLock = timeMs;
try {
getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
} catch (RemoteException e) {
Slog.w(TAG, "Failure talking with power manager", e);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
public long getMaximumTimeToLock(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
long time = 0;
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return admin != null ? admin.maximumTimeToUnlock : time;
}
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (time == 0) {
time = admin.maximumTimeToUnlock;
} else if (admin.maximumTimeToUnlock != 0
&& time > admin.maximumTimeToUnlock) {
time = admin.maximumTimeToUnlock;
}
}
return time;
}
}
public void lockNow() {
if (!mHasFeature) {
return;
}
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
getActiveAdminForCallerLocked(null,
DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
lockNowUnchecked();
}
}
private void lockNowUnchecked() {
long ident = Binder.clearCallingIdentity();
try {
// Power off the display
getIPowerManager().goToSleep(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN);
// Ensure the device is locked
getWindowManager().lockNow(null);
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private boolean isExtStorageEncrypted() {
String state = SystemProperties.get("vold.decrypt");
return !"".equals(state);
}
public boolean installCaCert(byte[] certBuffer) throws RemoteException {
mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
KeyChainConnection keyChainConnection = null;
byte[] pemCert;
try {
X509Certificate cert = parseCert(certBuffer);
pemCert = Credentials.convertToPem(cert);
} catch (CertificateException ce) {
Log.e(TAG, "Problem converting cert", ce);
return false;
} catch (IOException ioe) {
Log.e(TAG, "Problem reading cert", ioe);
return false;
}
try {
keyChainConnection = KeyChain.bind(mContext);
try {
keyChainConnection.getService().installCaCertificate(pemCert);
return true;
} finally {
if (keyChainConnection != null) {
keyChainConnection.close();
keyChainConnection = null;
}
}
} catch (InterruptedException e1) {
Log.w(TAG, "installCaCertsToKeyChain(): ", e1);
Thread.currentThread().interrupt();
}
return false;
}
private static X509Certificate parseCert(byte[] certBuffer)
throws CertificateException, IOException {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
return (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(
certBuffer));
}
public void uninstallCaCert(final byte[] certBuffer) {
mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null);
TrustedCertificateStore certStore = new TrustedCertificateStore();
String alias = null;
try {
X509Certificate cert = parseCert(certBuffer);
alias = certStore.getCertificateAlias(cert);
} catch (CertificateException ce) {
Log.e(TAG, "Problem creating X509Certificate", ce);
return;
} catch (IOException ioe) {
Log.e(TAG, "Problem reading certificate", ioe);
return;
}
try {
KeyChainConnection keyChainConnection = KeyChain.bind(mContext);
IKeyChainService service = keyChainConnection.getService();
try {
service.deleteCaCertificate(alias);
} catch (RemoteException e) {
Log.e(TAG, "from CaCertUninstaller: ", e);
} finally {
keyChainConnection.close();
keyChainConnection = null;
}
} catch (InterruptedException ie) {
Log.w(TAG, "CaCertUninstaller: ", ie);
Thread.currentThread().interrupt();
}
}
void wipeDataLocked(int flags) {
// If the SD card is encrypted and non-removable, we have to force a wipe.
boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0;
// Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated.
if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
intent.putExtra(ExternalStorageFormatter.EXTRA_ALWAYS_RESET, true);
intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
mWakeLock.acquire(10000);
mContext.startService(intent);
} else {
try {
RecoverySystem.rebootWipeUserData(mContext);
} catch (IOException e) {
Slog.w(TAG, "Failed requesting data wipe", e);
}
}
}
public void wipeData(int flags, final int userHandle) {
if (!mHasFeature) {
return;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
getActiveAdminForCallerLocked(null,
DeviceAdminInfo.USES_POLICY_WIPE_DATA);
long ident = Binder.clearCallingIdentity();
try {
wipeDeviceOrUserLocked(flags, userHandle);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
private void wipeDeviceOrUserLocked(int flags, final int userHandle) {
if (userHandle == UserHandle.USER_OWNER) {
wipeDataLocked(flags);
} else {
lockNowUnchecked();
mHandler.post(new Runnable() {
public void run() {
try {
ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
((UserManager) mContext.getSystemService(Context.USER_SERVICE))
.removeUser(userHandle);
} catch (RemoteException re) {
// Shouldn't happen
}
}
});
}
}
public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) {
if (!mHasFeature) {
return;
}
enforceCrossUserPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
synchronized (this) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(comp, userHandle);
if (admin == null) {
try {
result.sendResult(null);
} catch (RemoteException e) {
}
return;
}
Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
intent.setComponent(admin.info.getComponent());
mContext.sendOrderedBroadcastAsUser(intent, new UserHandle(userHandle),
null, new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
try {
result.sendResult(getResultExtras(false));
} catch (RemoteException e) {
}
}
}, null, Activity.RESULT_OK, null, null);
}
}
public void setActivePasswordState(int quality, int length, int letters, int uppercase,
int lowercase, int numbers, int symbols, int nonletter, int userHandle) {
if (!mHasFeature) {
return;
}
enforceCrossUserPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
DevicePolicyData p = getUserData(userHandle);
validateQualityConstant(quality);
synchronized (this) {
if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length
|| p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters
|| p.mActivePasswordUpperCase != uppercase
|| p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers
|| p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) {
long ident = Binder.clearCallingIdentity();
try {
p.mActivePasswordQuality = quality;
p.mActivePasswordLength = length;
p.mActivePasswordLetters = letters;
p.mActivePasswordLowerCase = lowercase;
p.mActivePasswordUpperCase = uppercase;
p.mActivePasswordNumeric = numbers;
p.mActivePasswordSymbols = symbols;
p.mActivePasswordNonLetter = nonletter;
p.mFailedPasswordAttempts = 0;
saveSettingsLocked(userHandle);
updatePasswordExpirationsLocked(userHandle);
setExpirationAlarmCheckLocked(mContext, p);
sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
}
/**
* Called any time the device password is updated. Resets all password expiration clocks.
*/
private void updatePasswordExpirationsLocked(int userHandle) {
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
if (N > 0) {
for (int i=0; i<N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
long timeout = admin.passwordExpirationTimeout;
long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
admin.passwordExpirationDate = expiration;
}
}
saveSettingsLocked(userHandle);
}
}
public void reportFailedPasswordAttempt(int userHandle) {
enforceCrossUserPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
long ident = Binder.clearCallingIdentity();
try {
policy.mFailedPasswordAttempts++;
saveSettingsLocked(userHandle);
if (mHasFeature) {
int max = getMaximumFailedPasswordsForWipe(null, userHandle);
if (max > 0 && policy.mFailedPasswordAttempts >= max) {
wipeDeviceOrUserLocked(0, userHandle);
}
sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
public void reportSuccessfulPasswordAttempt(int userHandle) {
enforceCrossUserPermission(userHandle);
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BIND_DEVICE_ADMIN, null);
synchronized (this) {
DevicePolicyData policy = getUserData(userHandle);
if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) {
long ident = Binder.clearCallingIdentity();
try {
policy.mFailedPasswordAttempts = 0;
policy.mPasswordOwner = -1;
saveSettingsLocked(userHandle);
if (mHasFeature) {
sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
}
public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
String exclusionList, int userHandle) {
if (!mHasFeature) {
return null;
}
enforceCrossUserPermission(userHandle);
synchronized(this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
// Only check if owner has set global proxy. We don't allow other users to set it.
DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
// Scan through active admins and find if anyone has already
// set the global proxy.
Set<ComponentName> compSet = policy.mAdminMap.keySet();
for (ComponentName component : compSet) {
ActiveAdmin ap = policy.mAdminMap.get(component);
if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
// Another admin already sets the global proxy
// Return it to the caller.
return component;
}
}
// If the user is not the owner, don't set the global proxy. Fail silently.
if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
Slog.w(TAG, "Only the owner is allowed to set the global proxy. User "
+ userHandle + " is not permitted.");
return null;
}
if (proxySpec == null) {
admin.specifiesGlobalProxy = false;
admin.globalProxySpec = null;
admin.globalProxyExclusionList = null;
} else {
admin.specifiesGlobalProxy = true;
admin.globalProxySpec = proxySpec;
admin.globalProxyExclusionList = exclusionList;
}
// Reset the global proxy accordingly
// Do this using system permissions, as apps cannot write to secure settings
long origId = Binder.clearCallingIdentity();
resetGlobalProxyLocked(policy);
Binder.restoreCallingIdentity(origId);
return null;
}
}
public ComponentName getGlobalProxyAdmin(int userHandle) {
if (!mHasFeature) {
return null;
}
enforceCrossUserPermission(userHandle);
synchronized(this) {
DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
// Scan through active admins and find if anyone has already
// set the global proxy.
final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
ActiveAdmin ap = policy.mAdminList.get(i);
if (ap.specifiesGlobalProxy) {
// Device admin sets the global proxy
// Return it to the caller.
return ap.info.getComponent();
}
}
}
// No device admin sets the global proxy.
return null;
}
private void resetGlobalProxyLocked(DevicePolicyData policy) {
final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
ActiveAdmin ap = policy.mAdminList.get(i);
if (ap.specifiesGlobalProxy) {
saveGlobalProxyLocked(ap.globalProxySpec, ap.globalProxyExclusionList);
return;
}
}
// No device admins defining global proxies - reset global proxy settings to none
saveGlobalProxyLocked(null, null);
}
private void saveGlobalProxyLocked(String proxySpec, String exclusionList) {
if (exclusionList == null) {
exclusionList = "";
}
if (proxySpec == null) {
proxySpec = "";
}
// Remove white spaces
proxySpec = proxySpec.trim();
String data[] = proxySpec.split(":");
int proxyPort = 8080;
if (data.length > 1) {
try {
proxyPort = Integer.parseInt(data[1]);
} catch (NumberFormatException e) {}
}
exclusionList = exclusionList.trim();
ContentResolver res = mContext.getContentResolver();
ProxyProperties proxyProperties = new ProxyProperties(data[0], proxyPort, exclusionList);
if (!proxyProperties.isValid()) {
Slog.e(TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString());
return;
}
Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]);
Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, proxyPort);
Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
exclusionList);
}
/**
* Set the storage encryption request for a single admin. Returns the new total request
* status (for all admins).
*/
public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) {
if (!mHasFeature) {
return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
// Check for permissions
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
// Only owner can set storage encryption
if (userHandle != UserHandle.USER_OWNER
|| UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
Slog.w(TAG, "Only owner is allowed to set storage encryption. User "
+ UserHandle.getCallingUserId() + " is not permitted.");
return 0;
}
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_ENCRYPTED_STORAGE);
// Quick exit: If the filesystem does not support encryption, we can exit early.
if (!isEncryptionSupported()) {
return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
}
// (1) Record the value for the admin so it's sticky
if (ap.encryptionRequested != encrypt) {
ap.encryptionRequested = encrypt;
saveSettingsLocked(userHandle);
}
DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
// (2) Compute "max" for all admins
boolean newRequested = false;
final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
newRequested |= policy.mAdminList.get(i).encryptionRequested;
}
// Notify OS of new request
setEncryptionRequested(newRequested);
// Return the new global request status
return newRequested
? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
: DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
}
}
/**
* Get the current storage encryption request status for a given admin, or aggregate of all
* active admins.
*/
public boolean getStorageEncryption(ComponentName who, int userHandle) {
if (!mHasFeature) {
return false;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
// Check for permissions if a particular caller is specified
if (who != null) {
// When checking for a single caller, status is based on caller's request
ActiveAdmin ap = getActiveAdminUncheckedLocked(who, userHandle);
return ap != null ? ap.encryptionRequested : false;
}
// If no particular caller is specified, return the aggregate set of requests.
// This is short circuited by returning true on the first hit.
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
if (policy.mAdminList.get(i).encryptionRequested) {
return true;
}
}
return false;
}
}
/**
* Get the current encryption status of the device.
*/
public int getStorageEncryptionStatus(int userHandle) {
if (!mHasFeature) {
// Ok to return current status.
}
enforceCrossUserPermission(userHandle);
return getEncryptionStatus();
}
/**
* Hook to low-levels: This should report if the filesystem supports encrypted storage.
*/
private boolean isEncryptionSupported() {
// Note, this can be implemented as
// return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
// But is provided as a separate internal method if there's a faster way to do a
// simple check for supported-or-not.
return getEncryptionStatus() != DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
}
/**
* Hook to low-levels: Reporting the current status of encryption.
* @return A value such as {@link DevicePolicyManager#ENCRYPTION_STATUS_UNSUPPORTED} or
* {@link DevicePolicyManager#ENCRYPTION_STATUS_INACTIVE} or
* {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
*/
private int getEncryptionStatus() {
String status = SystemProperties.get("ro.crypto.state", "unsupported");
if ("encrypted".equalsIgnoreCase(status)) {
return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE;
} else if ("unencrypted".equalsIgnoreCase(status)) {
return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
} else {
return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
}
}
/**
* Hook to low-levels: If needed, record the new admin setting for encryption.
*/
private void setEncryptionRequested(boolean encrypt) {
}
/**
* The system property used to share the state of the camera. The native camera service
* is expected to read this property and act accordingly.
*/
public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled";
/**
* Disables all device cameras according to the specified admin.
*/
public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) {
if (!mHasFeature) {
return;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
if (ap.disableCamera != disabled) {
ap.disableCamera = disabled;
saveSettingsLocked(userHandle);
}
syncDeviceCapabilitiesLocked(getUserData(userHandle));
}
}
/**
* Gets whether or not all device cameras are disabled for a given admin, or disabled for any
* active admins.
*/
public boolean getCameraDisabled(ComponentName who, int userHandle) {
if (!mHasFeature) {
return false;
}
synchronized (this) {
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return (admin != null) ? admin.disableCamera : false;
}
DevicePolicyData policy = getUserData(userHandle);
// Determine whether or not the device camera is disabled for any active admins.
final int N = policy.mAdminList.size();
for (int i = 0; i < N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
if (admin.disableCamera) {
return true;
}
}
return false;
}
}
/**
* Selectively disable keyguard features.
*/
public void setKeyguardDisabledFeatures(ComponentName who, int which, int userHandle) {
if (!mHasFeature) {
return;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
ActiveAdmin ap = getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
if (ap.disabledKeyguardFeatures != which) {
ap.disabledKeyguardFeatures = which;
saveSettingsLocked(userHandle);
}
syncDeviceCapabilitiesLocked(getUserData(userHandle));
}
}
/**
* Gets the disabled state for features in keyguard for the given admin,
* or the aggregate of all active admins if who is null.
*/
public int getKeyguardDisabledFeatures(ComponentName who, int userHandle) {
if (!mHasFeature) {
return 0;
}
enforceCrossUserPermission(userHandle);
synchronized (this) {
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
return (admin != null) ? admin.disabledKeyguardFeatures : 0;
}
// Determine which keyguard features are disabled for any active admins.
DevicePolicyData policy = getUserData(userHandle);
final int N = policy.mAdminList.size();
int which = 0;
for (int i = 0; i < N; i++) {
ActiveAdmin admin = policy.mAdminList.get(i);
which |= admin.disabledKeyguardFeatures;
}
return which;
}
}
@Override
public boolean setDeviceOwner(String packageName, String ownerName) {
if (!mHasFeature) {
return false;
}
if (packageName == null
|| !DeviceOwner.isInstalled(packageName, mContext.getPackageManager())) {
throw new IllegalArgumentException("Invalid package name " + packageName
+ " for device owner");
}
synchronized (this) {
if (mDeviceOwner == null && !isDeviceProvisioned()) {
mDeviceOwner = new DeviceOwner(packageName, ownerName);
mDeviceOwner.writeOwnerFile();
return true;
} else {
throw new IllegalStateException("Trying to set device owner to " + packageName
+ ", owner=" + mDeviceOwner.getPackageName()
+ ", device_provisioned=" + isDeviceProvisioned());
}
}
}
@Override
public boolean isDeviceOwner(String packageName) {
if (!mHasFeature) {
return false;
}
synchronized (this) {
return mDeviceOwner != null
&& mDeviceOwner.getPackageName().equals(packageName);
}
}
@Override
public String getDeviceOwner() {
if (!mHasFeature) {
return null;
}
synchronized (this) {
if (mDeviceOwner != null) {
return mDeviceOwner.getPackageName();
}
}
return null;
}
@Override
public String getDeviceOwnerName() {
if (!mHasFeature) {
return null;
}
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
synchronized (this) {
if (mDeviceOwner != null) {
return mDeviceOwner.getName();
}
}
return null;
}
private boolean isDeviceProvisioned() {
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0) > 0;
}
private void enforceCrossUserPermission(int userHandle) {
if (userHandle < 0) {
throw new IllegalArgumentException("Invalid userId " + userHandle);
}
final int callingUid = Binder.getCallingUid();
if (userHandle == UserHandle.getUserId(callingUid)) return;
if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have"
+ " INTERACT_ACROSS_USERS_FULL permission");
}
}
private void enableIfNecessary(String packageName, int userId) {
try {
IPackageManager ipm = AppGlobals.getPackageManager();
ApplicationInfo ai = ipm.getApplicationInfo(packageName,
PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
userId);
if (ai.enabledSetting
== PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
ipm.setApplicationEnabledSetting(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
PackageManager.DONT_KILL_APP, userId, "DevicePolicyManager");
}
} catch (RemoteException e) {
}
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid());
return;
}
final Printer p = new PrintWriterPrinter(pw);
synchronized (this) {
p.println("Current Device Policy Manager state:");
int userCount = mUserData.size();
for (int u = 0; u < userCount; u++) {
DevicePolicyData policy = getUserData(mUserData.keyAt(u));
p.println(" Enabled Device Admins (User " + policy.mUserHandle + "):");
final int N = policy.mAdminList.size();
for (int i=0; i<N; i++) {
ActiveAdmin ap = policy.mAdminList.get(i);
if (ap != null) {
pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString());
pw.println(":");
ap.dump(" ", pw);
}
}
pw.println(" ");
pw.print(" mPasswordOwner="); pw.println(policy.mPasswordOwner);
}
}
}
static class DeviceOwner {
private static final String DEVICE_OWNER_XML = "device_owner.xml";
private static final String TAG_DEVICE_OWNER = "device-owner";
private static final String ATTR_NAME = "name";
private static final String ATTR_PACKAGE = "package";
private String mPackageName;
private String mOwnerName;
DeviceOwner() {
readOwnerFile();
}
DeviceOwner(String packageName, String ownerName) {
this.mPackageName = packageName;
this.mOwnerName = ownerName;
}
static boolean isRegistered() {
return new File(Environment.getSystemSecureDirectory(),
DEVICE_OWNER_XML).exists();
}
String getPackageName() {
return mPackageName;
}
String getName() {
return mOwnerName;
}
static boolean isInstalled(String packageName, PackageManager pm) {
try {
PackageInfo pi;
if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
return true;
}
}
} catch (NameNotFoundException nnfe) {
Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
}
return false;
}
void readOwnerFile() {
AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
DEVICE_OWNER_XML));
try {
FileInputStream input = file.openRead();
XmlPullParser parser = Xml.newPullParser();
parser.setInput(input, null);
int type;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& type != XmlPullParser.START_TAG) {
}
String tag = parser.getName();
if (!TAG_DEVICE_OWNER.equals(tag)) {
throw new XmlPullParserException(
"Device Owner file does not start with device-owner tag: found " + tag);
}
mPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
mOwnerName = parser.getAttributeValue(null, ATTR_NAME);
input.close();
} catch (XmlPullParserException xppe) {
Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
} catch (IOException ioe) {
Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
}
}
void writeOwnerFile() {
synchronized (this) {
writeOwnerFileLocked();
}
}
private void writeOwnerFileLocked() {
AtomicFile file = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
DEVICE_OWNER_XML));
try {
FileOutputStream output = file.startWrite();
XmlSerializer out = new FastXmlSerializer();
out.setOutput(output, "utf-8");
out.startDocument(null, true);
out.startTag(null, TAG_DEVICE_OWNER);
out.attribute(null, ATTR_PACKAGE, mPackageName);
if (mOwnerName != null) {
out.attribute(null, ATTR_NAME, mOwnerName);
}
out.endTag(null, TAG_DEVICE_OWNER);
out.endDocument();
out.flush();
file.finishWrite(output);
} catch (IOException ioe) {
Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
}
}
}
}