Home | History | Annotate | Download | only in server
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server;
     18 
     19 import com.android.internal.content.PackageMonitor;
     20 import com.android.internal.util.FastXmlSerializer;
     21 import com.android.internal.util.JournaledFile;
     22 import com.android.internal.util.XmlUtils;
     23 import com.android.internal.widget.LockPatternUtils;
     24 
     25 import org.xmlpull.v1.XmlPullParser;
     26 import org.xmlpull.v1.XmlPullParserException;
     27 import org.xmlpull.v1.XmlSerializer;
     28 
     29 import android.app.Activity;
     30 import android.app.admin.DeviceAdminInfo;
     31 import android.app.admin.DeviceAdminReceiver;
     32 import android.app.admin.DevicePolicyManager;
     33 import android.app.admin.IDevicePolicyManager;
     34 import android.content.BroadcastReceiver;
     35 import android.content.ComponentName;
     36 import android.content.Context;
     37 import android.content.Intent;
     38 import android.content.pm.PackageManager;
     39 import android.content.pm.ResolveInfo;
     40 import android.content.pm.PackageManager.NameNotFoundException;
     41 import android.os.Binder;
     42 import android.os.IBinder;
     43 import android.os.IPowerManager;
     44 import android.os.RecoverySystem;
     45 import android.os.RemoteCallback;
     46 import android.os.RemoteException;
     47 import android.os.ServiceManager;
     48 import android.os.SystemClock;
     49 import android.util.Slog;
     50 import android.util.PrintWriterPrinter;
     51 import android.util.Printer;
     52 import android.util.Xml;
     53 import android.view.WindowManagerPolicy;
     54 
     55 import java.io.File;
     56 import java.io.FileDescriptor;
     57 import java.io.FileInputStream;
     58 import java.io.FileOutputStream;
     59 import java.io.IOException;
     60 import java.io.PrintWriter;
     61 import java.util.ArrayList;
     62 import java.util.HashMap;
     63 import java.util.List;
     64 
     65 /**
     66  * Implementation of the device policy APIs.
     67  */
     68 public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
     69     static final String TAG = "DevicePolicyManagerService";
     70 
     71     final Context mContext;
     72     final MyPackageMonitor mMonitor;
     73 
     74     IPowerManager mIPowerManager;
     75 
     76     int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
     77     int mActivePasswordLength = 0;
     78     int mFailedPasswordAttempts = 0;
     79 
     80     int mPasswordOwner = -1;
     81 
     82     final HashMap<ComponentName, ActiveAdmin> mAdminMap
     83             = new HashMap<ComponentName, ActiveAdmin>();
     84     final ArrayList<ActiveAdmin> mAdminList
     85             = new ArrayList<ActiveAdmin>();
     86 
     87     static class ActiveAdmin {
     88         final DeviceAdminInfo info;
     89 
     90         int passwordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
     91         int minimumPasswordLength = 0;
     92         long maximumTimeToUnlock = 0;
     93         int maximumFailedPasswordsForWipe = 0;
     94 
     95         ActiveAdmin(DeviceAdminInfo _info) {
     96             info = _info;
     97         }
     98 
     99         int getUid() { return info.getActivityInfo().applicationInfo.uid; }
    100 
    101         void writeToXml(XmlSerializer out)
    102                 throws IllegalArgumentException, IllegalStateException, IOException {
    103             out.startTag(null, "policies");
    104             info.writePoliciesToXml(out);
    105             out.endTag(null, "policies");
    106             if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
    107                 out.startTag(null, "password-quality");
    108                 out.attribute(null, "value", Integer.toString(passwordQuality));
    109                 out.endTag(null, "password-quality");
    110                 if (minimumPasswordLength > 0) {
    111                     out.startTag(null, "min-password-length");
    112                     out.attribute(null, "value", Integer.toString(minimumPasswordLength));
    113                     out.endTag(null, "mn-password-length");
    114                 }
    115             }
    116             if (maximumTimeToUnlock != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
    117                 out.startTag(null, "max-time-to-unlock");
    118                 out.attribute(null, "value", Long.toString(maximumTimeToUnlock));
    119                 out.endTag(null, "max-time-to-unlock");
    120             }
    121             if (maximumFailedPasswordsForWipe != 0) {
    122                 out.startTag(null, "max-failed-password-wipe");
    123                 out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
    124                 out.endTag(null, "max-failed-password-wipe");
    125             }
    126         }
    127 
    128         void readFromXml(XmlPullParser parser)
    129                 throws XmlPullParserException, IOException {
    130             int outerDepth = parser.getDepth();
    131             int type;
    132             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
    133                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
    134                 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
    135                     continue;
    136                 }
    137                 String tag = parser.getName();
    138                 if ("policies".equals(tag)) {
    139                     info.readPoliciesFromXml(parser);
    140                 } else if ("password-quality".equals(tag)) {
    141                     passwordQuality = Integer.parseInt(
    142                             parser.getAttributeValue(null, "value"));
    143                 } else if ("min-password-length".equals(tag)) {
    144                     minimumPasswordLength = Integer.parseInt(
    145                             parser.getAttributeValue(null, "value"));
    146                 } else if ("max-time-to-unlock".equals(tag)) {
    147                     maximumTimeToUnlock = Long.parseLong(
    148                             parser.getAttributeValue(null, "value"));
    149                 } else if ("max-failed-password-wipe".equals(tag)) {
    150                     maximumFailedPasswordsForWipe = Integer.parseInt(
    151                             parser.getAttributeValue(null, "value"));
    152                 } else {
    153                     Slog.w(TAG, "Unknown admin tag: " + tag);
    154                 }
    155                 XmlUtils.skipCurrentTag(parser);
    156             }
    157         }
    158 
    159         void dump(String prefix, PrintWriter pw) {
    160             pw.print(prefix); pw.print("uid="); pw.println(getUid());
    161             pw.print(prefix); pw.println("policies:");
    162             ArrayList<DeviceAdminInfo.PolicyInfo> pols = info.getUsedPolicies();
    163             if (pols != null) {
    164                 for (int i=0; i<pols.size(); i++) {
    165                     pw.print(prefix); pw.print("  "); pw.println(pols.get(i).tag);
    166                 }
    167             }
    168             pw.print(prefix); pw.print("passwordQuality=0x");
    169                     pw.print(Integer.toHexString(passwordQuality));
    170                     pw.print(" minimumPasswordLength=");
    171                     pw.println(minimumPasswordLength);
    172             pw.print(prefix); pw.print("maximumTimeToUnlock=");
    173                     pw.println(maximumTimeToUnlock);
    174             pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
    175                     pw.println(maximumFailedPasswordsForWipe);
    176         }
    177     }
    178 
    179     class MyPackageMonitor extends PackageMonitor {
    180         public void onSomePackagesChanged() {
    181             synchronized (DevicePolicyManagerService.this) {
    182                 boolean removed = false;
    183                 for (int i=mAdminList.size()-1; i>=0; i--) {
    184                     ActiveAdmin aa = mAdminList.get(i);
    185                     int change = isPackageDisappearing(aa.info.getPackageName());
    186                     if (change == PACKAGE_PERMANENT_CHANGE
    187                             || change == PACKAGE_TEMPORARY_CHANGE) {
    188                         Slog.w(TAG, "Admin unexpectedly uninstalled: "
    189                                 + aa.info.getComponent());
    190                         removed = true;
    191                         mAdminList.remove(i);
    192                     } else if (isPackageModified(aa.info.getPackageName())) {
    193                         try {
    194                             mContext.getPackageManager().getReceiverInfo(
    195                                     aa.info.getComponent(), 0);
    196                         } catch (NameNotFoundException e) {
    197                             Slog.w(TAG, "Admin package change removed component: "
    198                                     + aa.info.getComponent());
    199                             removed = true;
    200                             mAdminList.remove(i);
    201                         }
    202                     }
    203                 }
    204                 if (removed) {
    205                     validatePasswordOwnerLocked();
    206                 }
    207             }
    208         }
    209     }
    210 
    211     /**
    212      * Instantiates the service.
    213      */
    214     public DevicePolicyManagerService(Context context) {
    215         mContext = context;
    216         mMonitor = new MyPackageMonitor();
    217         mMonitor.register(context, true);
    218     }
    219 
    220     private IPowerManager getIPowerManager() {
    221         if (mIPowerManager == null) {
    222             IBinder b = ServiceManager.getService(Context.POWER_SERVICE);
    223             mIPowerManager = IPowerManager.Stub.asInterface(b);
    224         }
    225         return mIPowerManager;
    226     }
    227 
    228     ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) {
    229         ActiveAdmin admin = mAdminMap.get(who);
    230         if (admin != null
    231                 && who.getPackageName().equals(admin.info.getActivityInfo().packageName)
    232                 && who.getClassName().equals(admin.info.getActivityInfo().name)) {
    233             return admin;
    234         }
    235         return null;
    236     }
    237 
    238     ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
    239             throws SecurityException {
    240         final int callingUid = Binder.getCallingUid();
    241         if (who != null) {
    242             ActiveAdmin admin = mAdminMap.get(who);
    243             if (admin == null) {
    244                 throw new SecurityException("No active admin " + who);
    245             }
    246             if (admin.getUid() != callingUid) {
    247                 throw new SecurityException("Admin " + who + " is not owned by uid "
    248                         + Binder.getCallingUid());
    249             }
    250             if (!admin.info.usesPolicy(reqPolicy)) {
    251                 throw new SecurityException("Admin " + admin.info.getComponent()
    252                         + " did not specify uses-policy for: "
    253                         + admin.info.getTagForPolicy(reqPolicy));
    254             }
    255             return admin;
    256         } else {
    257             final int N = mAdminList.size();
    258             for (int i=0; i<N; i++) {
    259                 ActiveAdmin admin = mAdminList.get(i);
    260                 if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) {
    261                     return admin;
    262                 }
    263             }
    264             throw new SecurityException("No active admin owned by uid "
    265                     + Binder.getCallingUid() + " for policy #" + reqPolicy);
    266         }
    267     }
    268 
    269     void sendAdminCommandLocked(ActiveAdmin admin, String action) {
    270         Intent intent = new Intent(action);
    271         intent.setComponent(admin.info.getComponent());
    272         mContext.sendBroadcast(intent);
    273     }
    274 
    275     void sendAdminCommandLocked(String action, int reqPolicy) {
    276         final int N = mAdminList.size();
    277         if (N > 0) {
    278             for (int i=0; i<N; i++) {
    279                 ActiveAdmin admin = mAdminList.get(i);
    280                 if (admin.info.usesPolicy(reqPolicy)) {
    281                     sendAdminCommandLocked(admin, action);
    282                 }
    283             }
    284         }
    285     }
    286 
    287     void removeActiveAdminLocked(ComponentName adminReceiver) {
    288         ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
    289         if (admin != null) {
    290             sendAdminCommandLocked(admin,
    291                     DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
    292             // XXX need to wait for it to complete.
    293             mAdminList.remove(admin);
    294             mAdminMap.remove(adminReceiver);
    295             validatePasswordOwnerLocked();
    296         }
    297     }
    298 
    299     public DeviceAdminInfo findAdmin(ComponentName adminName) {
    300         Intent resolveIntent = new Intent();
    301         resolveIntent.setComponent(adminName);
    302         List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers(
    303                 resolveIntent, PackageManager.GET_META_DATA);
    304         if (infos == null || infos.size() <= 0) {
    305             throw new IllegalArgumentException("Unknown admin: " + adminName);
    306         }
    307 
    308         try {
    309             return new DeviceAdminInfo(mContext, infos.get(0));
    310         } catch (XmlPullParserException e) {
    311             Slog.w(TAG, "Bad device admin requested: " + adminName, e);
    312             return null;
    313         } catch (IOException e) {
    314             Slog.w(TAG, "Bad device admin requested: " + adminName, e);
    315             return null;
    316         }
    317     }
    318 
    319     private static JournaledFile makeJournaledFile() {
    320         final String base = "/data/system/device_policies.xml";
    321         return new JournaledFile(new File(base), new File(base + ".tmp"));
    322     }
    323 
    324     private void saveSettingsLocked() {
    325         JournaledFile journal = makeJournaledFile();
    326         FileOutputStream stream = null;
    327         try {
    328             stream = new FileOutputStream(journal.chooseForWrite(), false);
    329             XmlSerializer out = new FastXmlSerializer();
    330             out.setOutput(stream, "utf-8");
    331             out.startDocument(null, true);
    332 
    333             out.startTag(null, "policies");
    334 
    335             final int N = mAdminList.size();
    336             for (int i=0; i<N; i++) {
    337                 ActiveAdmin ap = mAdminList.get(i);
    338                 if (ap != null) {
    339                     out.startTag(null, "admin");
    340                     out.attribute(null, "name", ap.info.getComponent().flattenToString());
    341                     ap.writeToXml(out);
    342                     out.endTag(null, "admin");
    343                 }
    344             }
    345 
    346             if (mPasswordOwner >= 0) {
    347                 out.startTag(null, "password-owner");
    348                 out.attribute(null, "value", Integer.toString(mPasswordOwner));
    349                 out.endTag(null, "password-owner");
    350             }
    351 
    352             if (mFailedPasswordAttempts != 0) {
    353                 out.startTag(null, "failed-password-attempts");
    354                 out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts));
    355                 out.endTag(null, "failed-password-attempts");
    356             }
    357 
    358             if (mActivePasswordQuality != 0 || mActivePasswordLength != 0) {
    359                 out.startTag(null, "active-password");
    360                 out.attribute(null, "quality", Integer.toString(mActivePasswordQuality));
    361                 out.attribute(null, "length", Integer.toString(mActivePasswordLength));
    362                 out.endTag(null, "active-password");
    363             }
    364 
    365             out.endTag(null, "policies");
    366 
    367             out.endDocument();
    368             stream.close();
    369             journal.commit();
    370             sendChangedNotification();
    371         } catch (IOException e) {
    372             try {
    373                 if (stream != null) {
    374                     stream.close();
    375                 }
    376             } catch (IOException ex) {
    377                 // Ignore
    378             }
    379             journal.rollback();
    380         }
    381     }
    382 
    383     private void sendChangedNotification() {
    384         Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
    385         intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    386         mContext.sendBroadcast(intent);
    387     }
    388 
    389     private void loadSettingsLocked() {
    390         JournaledFile journal = makeJournaledFile();
    391         FileInputStream stream = null;
    392         File file = journal.chooseForRead();
    393         try {
    394             stream = new FileInputStream(file);
    395             XmlPullParser parser = Xml.newPullParser();
    396             parser.setInput(stream, null);
    397 
    398             int type;
    399             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
    400                     && type != XmlPullParser.START_TAG) {
    401             }
    402             String tag = parser.getName();
    403             if (!"policies".equals(tag)) {
    404                 throw new XmlPullParserException(
    405                         "Settings do not start with policies tag: found " + tag);
    406             }
    407             type = parser.next();
    408             int outerDepth = parser.getDepth();
    409             while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
    410                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
    411                 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
    412                     continue;
    413                 }
    414                 tag = parser.getName();
    415                 if ("admin".equals(tag)) {
    416                     String name = parser.getAttributeValue(null, "name");
    417                     try {
    418                         DeviceAdminInfo dai = findAdmin(
    419                                 ComponentName.unflattenFromString(name));
    420                         if (dai != null) {
    421                             ActiveAdmin ap = new ActiveAdmin(dai);
    422                             ap.readFromXml(parser);
    423                             mAdminMap.put(ap.info.getComponent(), ap);
    424                             mAdminList.add(ap);
    425                         }
    426                     } catch (RuntimeException e) {
    427                         Slog.w(TAG, "Failed loading admin " + name, e);
    428                     }
    429                 } else if ("failed-password-attempts".equals(tag)) {
    430                     mFailedPasswordAttempts = Integer.parseInt(
    431                             parser.getAttributeValue(null, "value"));
    432                     XmlUtils.skipCurrentTag(parser);
    433                 } else if ("password-owner".equals(tag)) {
    434                     mPasswordOwner = Integer.parseInt(
    435                             parser.getAttributeValue(null, "value"));
    436                     XmlUtils.skipCurrentTag(parser);
    437                 } else if ("active-password".equals(tag)) {
    438                     mActivePasswordQuality = Integer.parseInt(
    439                             parser.getAttributeValue(null, "quality"));
    440                     mActivePasswordLength = Integer.parseInt(
    441                             parser.getAttributeValue(null, "length"));
    442                     XmlUtils.skipCurrentTag(parser);
    443                 } else {
    444                     Slog.w(TAG, "Unknown tag: " + tag);
    445                     XmlUtils.skipCurrentTag(parser);
    446                 }
    447             }
    448         } catch (NullPointerException e) {
    449             Slog.w(TAG, "failed parsing " + file + " " + e);
    450         } catch (NumberFormatException e) {
    451             Slog.w(TAG, "failed parsing " + file + " " + e);
    452         } catch (XmlPullParserException e) {
    453             Slog.w(TAG, "failed parsing " + file + " " + e);
    454         } catch (IOException e) {
    455             Slog.w(TAG, "failed parsing " + file + " " + e);
    456         } catch (IndexOutOfBoundsException e) {
    457             Slog.w(TAG, "failed parsing " + file + " " + e);
    458         }
    459         try {
    460             if (stream != null) {
    461                 stream.close();
    462             }
    463         } catch (IOException e) {
    464             // Ignore
    465         }
    466 
    467         // Validate that what we stored for the password quality matches
    468         // sufficiently what is currently set.  Note that this is only
    469         // a sanity check in case the two get out of sync; this should
    470         // never normally happen.
    471         LockPatternUtils utils = new LockPatternUtils(mContext);
    472         if (utils.getActivePasswordQuality() < mActivePasswordQuality) {
    473             Slog.w(TAG, "Active password quality 0x"
    474                     + Integer.toHexString(mActivePasswordQuality)
    475                     + " does not match actual quality 0x"
    476                     + Integer.toHexString(utils.getActivePasswordQuality()));
    477             mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
    478             mActivePasswordLength = 0;
    479         }
    480 
    481         validatePasswordOwnerLocked();
    482 
    483         long timeMs = getMaximumTimeToLock(null);
    484         if (timeMs <= 0) {
    485             timeMs = Integer.MAX_VALUE;
    486         }
    487         try {
    488             getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
    489         } catch (RemoteException e) {
    490             Slog.w(TAG, "Failure talking with power manager", e);
    491         }
    492     }
    493 
    494     static void validateQualityConstant(int quality) {
    495         switch (quality) {
    496             case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
    497             case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
    498             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
    499             case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
    500             case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
    501                 return;
    502         }
    503         throw new IllegalArgumentException("Invalid quality constant: 0x"
    504                 + Integer.toHexString(quality));
    505     }
    506 
    507     void validatePasswordOwnerLocked() {
    508         if (mPasswordOwner >= 0) {
    509             boolean haveOwner = false;
    510             for (int i=mAdminList.size()-1; i>=0; i--) {
    511                 if (mAdminList.get(i).getUid() == mPasswordOwner) {
    512                     haveOwner = true;
    513                     break;
    514                 }
    515             }
    516             if (!haveOwner) {
    517                 Slog.w(TAG, "Previous password owner " + mPasswordOwner
    518                         + " no longer active; disabling");
    519                 mPasswordOwner = -1;
    520             }
    521         }
    522     }
    523 
    524     public void systemReady() {
    525         synchronized (this) {
    526             loadSettingsLocked();
    527         }
    528     }
    529 
    530     public void setActiveAdmin(ComponentName adminReceiver) {
    531         mContext.enforceCallingOrSelfPermission(
    532                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
    533 
    534         DeviceAdminInfo info = findAdmin(adminReceiver);
    535         if (info == null) {
    536             throw new IllegalArgumentException("Bad admin: " + adminReceiver);
    537         }
    538         synchronized (this) {
    539             long ident = Binder.clearCallingIdentity();
    540             try {
    541                 if (getActiveAdminUncheckedLocked(adminReceiver) != null) {
    542                     throw new IllegalArgumentException("Admin is already added");
    543                 }
    544                 ActiveAdmin admin = new ActiveAdmin(info);
    545                 mAdminMap.put(adminReceiver, admin);
    546                 mAdminList.add(admin);
    547                 saveSettingsLocked();
    548                 sendAdminCommandLocked(admin,
    549                         DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED);
    550             } finally {
    551                 Binder.restoreCallingIdentity(ident);
    552             }
    553         }
    554     }
    555 
    556     public boolean isAdminActive(ComponentName adminReceiver) {
    557         synchronized (this) {
    558             return getActiveAdminUncheckedLocked(adminReceiver) != null;
    559         }
    560     }
    561 
    562     public List<ComponentName> getActiveAdmins() {
    563         synchronized (this) {
    564             final int N = mAdminList.size();
    565             if (N <= 0) {
    566                 return null;
    567             }
    568             ArrayList<ComponentName> res = new ArrayList<ComponentName>(N);
    569             for (int i=0; i<N; i++) {
    570                 res.add(mAdminList.get(i).info.getComponent());
    571             }
    572             return res;
    573         }
    574     }
    575 
    576     public boolean packageHasActiveAdmins(String packageName) {
    577         synchronized (this) {
    578             final int N = mAdminList.size();
    579             for (int i=0; i<N; i++) {
    580                 if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
    581                     return true;
    582                 }
    583             }
    584             return false;
    585         }
    586     }
    587 
    588     public void removeActiveAdmin(ComponentName adminReceiver) {
    589         synchronized (this) {
    590             ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
    591             if (admin == null) {
    592                 return;
    593             }
    594             if (admin.getUid() != Binder.getCallingUid()) {
    595                 mContext.enforceCallingOrSelfPermission(
    596                         android.Manifest.permission.BIND_DEVICE_ADMIN, null);
    597             }
    598             long ident = Binder.clearCallingIdentity();
    599             try {
    600                 removeActiveAdminLocked(adminReceiver);
    601             } finally {
    602                 Binder.restoreCallingIdentity(ident);
    603             }
    604         }
    605     }
    606 
    607     public void setPasswordQuality(ComponentName who, int quality) {
    608         validateQualityConstant(quality);
    609 
    610         synchronized (this) {
    611             if (who == null) {
    612                 throw new NullPointerException("ComponentName is null");
    613             }
    614             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
    615                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
    616             if (ap.passwordQuality != quality) {
    617                 ap.passwordQuality = quality;
    618                 saveSettingsLocked();
    619             }
    620         }
    621     }
    622 
    623     public int getPasswordQuality(ComponentName who) {
    624         synchronized (this) {
    625             int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
    626 
    627             if (who != null) {
    628                 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
    629                 return admin != null ? admin.passwordQuality : mode;
    630             }
    631 
    632             final int N = mAdminList.size();
    633             for  (int i=0; i<N; i++) {
    634                 ActiveAdmin admin = mAdminList.get(i);
    635                 if (mode < admin.passwordQuality) {
    636                     mode = admin.passwordQuality;
    637                 }
    638             }
    639             return mode;
    640         }
    641     }
    642 
    643     public void setPasswordMinimumLength(ComponentName who, int length) {
    644         synchronized (this) {
    645             if (who == null) {
    646                 throw new NullPointerException("ComponentName is null");
    647             }
    648             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
    649                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
    650             if (ap.minimumPasswordLength != length) {
    651                 ap.minimumPasswordLength = length;
    652                 saveSettingsLocked();
    653             }
    654         }
    655     }
    656 
    657     public int getPasswordMinimumLength(ComponentName who) {
    658         synchronized (this) {
    659             int length = 0;
    660 
    661             if (who != null) {
    662                 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
    663                 return admin != null ? admin.minimumPasswordLength : length;
    664             }
    665 
    666             final int N = mAdminList.size();
    667             for  (int i=0; i<N; i++) {
    668                 ActiveAdmin admin = mAdminList.get(i);
    669                 if (length < admin.minimumPasswordLength) {
    670                     length = admin.minimumPasswordLength;
    671                 }
    672             }
    673             return length;
    674         }
    675     }
    676 
    677     public boolean isActivePasswordSufficient() {
    678         synchronized (this) {
    679             // This API can only be called by an active device admin,
    680             // so try to retrieve it to check that the caller is one.
    681             getActiveAdminForCallerLocked(null,
    682                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
    683             return mActivePasswordQuality >= getPasswordQuality(null)
    684                     && mActivePasswordLength >= getPasswordMinimumLength(null);
    685         }
    686     }
    687 
    688     public int getCurrentFailedPasswordAttempts() {
    689         synchronized (this) {
    690             // This API can only be called by an active device admin,
    691             // so try to retrieve it to check that the caller is one.
    692             getActiveAdminForCallerLocked(null,
    693                     DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
    694             return mFailedPasswordAttempts;
    695         }
    696     }
    697 
    698     public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) {
    699         synchronized (this) {
    700             // This API can only be called by an active device admin,
    701             // so try to retrieve it to check that the caller is one.
    702             getActiveAdminForCallerLocked(who,
    703                     DeviceAdminInfo.USES_POLICY_WIPE_DATA);
    704             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
    705                     DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
    706             if (ap.maximumFailedPasswordsForWipe != num) {
    707                 ap.maximumFailedPasswordsForWipe = num;
    708                 saveSettingsLocked();
    709             }
    710         }
    711     }
    712 
    713     public int getMaximumFailedPasswordsForWipe(ComponentName who) {
    714         synchronized (this) {
    715             int count = 0;
    716 
    717             if (who != null) {
    718                 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
    719                 return admin != null ? admin.maximumFailedPasswordsForWipe : count;
    720             }
    721 
    722             final int N = mAdminList.size();
    723             for  (int i=0; i<N; i++) {
    724                 ActiveAdmin admin = mAdminList.get(i);
    725                 if (count == 0) {
    726                     count = admin.maximumFailedPasswordsForWipe;
    727                 } else if (admin.maximumFailedPasswordsForWipe != 0
    728                         && count > admin.maximumFailedPasswordsForWipe) {
    729                     count = admin.maximumFailedPasswordsForWipe;
    730                 }
    731             }
    732             return count;
    733         }
    734     }
    735 
    736     public boolean resetPassword(String password, int flags) {
    737         int quality;
    738         synchronized (this) {
    739             // This API can only be called by an active device admin,
    740             // so try to retrieve it to check that the caller is one.
    741             getActiveAdminForCallerLocked(null,
    742                     DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
    743             quality = getPasswordQuality(null);
    744             if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
    745                 int realQuality = LockPatternUtils.computePasswordQuality(password);
    746                 if (realQuality < quality) {
    747                     Slog.w(TAG, "resetPassword: password quality 0x"
    748                             + Integer.toHexString(quality)
    749                             + " does not meet required quality 0x"
    750                             + Integer.toHexString(quality));
    751                     return false;
    752                 }
    753                 quality = realQuality;
    754             }
    755             int length = getPasswordMinimumLength(null);
    756             if (password.length() < length) {
    757                 Slog.w(TAG, "resetPassword: password length " + password.length()
    758                         + " does not meet required length " + length);
    759                 return false;
    760             }
    761         }
    762 
    763         int callingUid = Binder.getCallingUid();
    764         if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) {
    765             Slog.w(TAG, "resetPassword: already set by another uid and not entered by user");
    766             return false;
    767         }
    768 
    769         // Don't do this with the lock held, because it is going to call
    770         // back in to the service.
    771         long ident = Binder.clearCallingIdentity();
    772         try {
    773             LockPatternUtils utils = new LockPatternUtils(mContext);
    774             utils.saveLockPassword(password, quality);
    775             synchronized (this) {
    776                 int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY)
    777                         != 0 ? callingUid : -1;
    778                 if (mPasswordOwner != newOwner) {
    779                     mPasswordOwner = newOwner;
    780                     saveSettingsLocked();
    781                 }
    782             }
    783         } finally {
    784             Binder.restoreCallingIdentity(ident);
    785         }
    786 
    787         return true;
    788     }
    789 
    790     public void setMaximumTimeToLock(ComponentName who, long timeMs) {
    791         synchronized (this) {
    792             if (who == null) {
    793                 throw new NullPointerException("ComponentName is null");
    794             }
    795             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
    796                     DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
    797             if (ap.maximumTimeToUnlock != timeMs) {
    798                 ap.maximumTimeToUnlock = timeMs;
    799 
    800                 long ident = Binder.clearCallingIdentity();
    801                 try {
    802                     saveSettingsLocked();
    803 
    804                     timeMs = getMaximumTimeToLock(null);
    805                     if (timeMs <= 0) {
    806                         timeMs = Integer.MAX_VALUE;
    807                     }
    808 
    809                     try {
    810                         getIPowerManager().setMaximumScreenOffTimeount((int)timeMs);
    811                     } catch (RemoteException e) {
    812                         Slog.w(TAG, "Failure talking with power manager", e);
    813                     }
    814                 } finally {
    815                     Binder.restoreCallingIdentity(ident);
    816                 }
    817             }
    818         }
    819     }
    820 
    821     public long getMaximumTimeToLock(ComponentName who) {
    822         synchronized (this) {
    823             long time = 0;
    824 
    825             if (who != null) {
    826                 ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
    827                 return admin != null ? admin.maximumTimeToUnlock : time;
    828             }
    829 
    830             final int N = mAdminList.size();
    831             for  (int i=0; i<N; i++) {
    832                 ActiveAdmin admin = mAdminList.get(i);
    833                 if (time == 0) {
    834                     time = admin.maximumTimeToUnlock;
    835                 } else if (admin.maximumTimeToUnlock != 0
    836                         && time > admin.maximumTimeToUnlock) {
    837                     time = admin.maximumTimeToUnlock;
    838                 }
    839             }
    840             return time;
    841         }
    842     }
    843 
    844     public void lockNow() {
    845         synchronized (this) {
    846             // This API can only be called by an active device admin,
    847             // so try to retrieve it to check that the caller is one.
    848             getActiveAdminForCallerLocked(null,
    849                     DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
    850             long ident = Binder.clearCallingIdentity();
    851             try {
    852                 mIPowerManager.goToSleepWithReason(SystemClock.uptimeMillis(),
    853                         WindowManagerPolicy.OFF_BECAUSE_OF_ADMIN);
    854             } catch (RemoteException e) {
    855             } finally {
    856                 Binder.restoreCallingIdentity(ident);
    857             }
    858         }
    859     }
    860 
    861     void wipeDataLocked(int flags) {
    862         try {
    863             RecoverySystem.rebootWipeUserData(mContext);
    864         } catch (IOException e) {
    865             Slog.w(TAG, "Failed requesting data wipe", e);
    866         }
    867     }
    868 
    869     public void wipeData(int flags) {
    870         synchronized (this) {
    871             // This API can only be called by an active device admin,
    872             // so try to retrieve it to check that the caller is one.
    873             getActiveAdminForCallerLocked(null,
    874                     DeviceAdminInfo.USES_POLICY_WIPE_DATA);
    875             long ident = Binder.clearCallingIdentity();
    876             try {
    877                 wipeDataLocked(flags);
    878             } finally {
    879                 Binder.restoreCallingIdentity(ident);
    880             }
    881         }
    882     }
    883 
    884     public void getRemoveWarning(ComponentName comp, final RemoteCallback result) {
    885         mContext.enforceCallingOrSelfPermission(
    886                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
    887 
    888         synchronized (this) {
    889             ActiveAdmin admin = getActiveAdminUncheckedLocked(comp);
    890             if (admin == null) {
    891                 try {
    892                     result.sendResult(null);
    893                 } catch (RemoteException e) {
    894                 }
    895                 return;
    896             }
    897             Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED);
    898             intent.setComponent(admin.info.getComponent());
    899             mContext.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
    900                 @Override
    901                 public void onReceive(Context context, Intent intent) {
    902                     try {
    903                         result.sendResult(getResultExtras(false));
    904                     } catch (RemoteException e) {
    905                     }
    906                 }
    907             }, null, Activity.RESULT_OK, null, null);
    908         }
    909     }
    910 
    911     public void setActivePasswordState(int quality, int length) {
    912         mContext.enforceCallingOrSelfPermission(
    913                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
    914 
    915         validateQualityConstant(quality);
    916 
    917         synchronized (this) {
    918             if (mActivePasswordQuality != quality || mActivePasswordLength != length
    919                     || mFailedPasswordAttempts != 0) {
    920                 long ident = Binder.clearCallingIdentity();
    921                 try {
    922                     mActivePasswordQuality = quality;
    923                     mActivePasswordLength = length;
    924                     mFailedPasswordAttempts = 0;
    925                     saveSettingsLocked();
    926                     sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
    927                             DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
    928                 } finally {
    929                     Binder.restoreCallingIdentity(ident);
    930                 }
    931             }
    932         }
    933     }
    934 
    935     public void reportFailedPasswordAttempt() {
    936         mContext.enforceCallingOrSelfPermission(
    937                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
    938 
    939         synchronized (this) {
    940             long ident = Binder.clearCallingIdentity();
    941             try {
    942                 mFailedPasswordAttempts++;
    943                 saveSettingsLocked();
    944                 int max = getMaximumFailedPasswordsForWipe(null);
    945                 if (max > 0 && mFailedPasswordAttempts >= max) {
    946                     wipeDataLocked(0);
    947                 }
    948                 sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED,
    949                         DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
    950             } finally {
    951                 Binder.restoreCallingIdentity(ident);
    952             }
    953         }
    954     }
    955 
    956     public void reportSuccessfulPasswordAttempt() {
    957         mContext.enforceCallingOrSelfPermission(
    958                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
    959 
    960         synchronized (this) {
    961             if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) {
    962                 long ident = Binder.clearCallingIdentity();
    963                 try {
    964                     mFailedPasswordAttempts = 0;
    965                     mPasswordOwner = -1;
    966                     saveSettingsLocked();
    967                     sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED,
    968                             DeviceAdminInfo.USES_POLICY_WATCH_LOGIN);
    969                 } finally {
    970                     Binder.restoreCallingIdentity(ident);
    971                 }
    972             }
    973         }
    974     }
    975 
    976     @Override
    977     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    978         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
    979                 != PackageManager.PERMISSION_GRANTED) {
    980 
    981             pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
    982                     + Binder.getCallingPid()
    983                     + ", uid=" + Binder.getCallingUid());
    984             return;
    985         }
    986 
    987         final Printer p = new PrintWriterPrinter(pw);
    988 
    989         synchronized (this) {
    990             p.println("Current Device Policy Manager state:");
    991 
    992             p.println("  Enabled Device Admins:");
    993             final int N = mAdminList.size();
    994             for (int i=0; i<N; i++) {
    995                 ActiveAdmin ap = mAdminList.get(i);
    996                 if (ap != null) {
    997                     pw.print("  "); pw.print(ap.info.getComponent().flattenToShortString());
    998                             pw.println(":");
    999                     ap.dump("    ", pw);
   1000                 }
   1001             }
   1002 
   1003             pw.println(" ");
   1004             pw.print("  mActivePasswordQuality=0x");
   1005                     pw.println(Integer.toHexString(mActivePasswordQuality));
   1006             pw.print("  mActivePasswordLength="); pw.println(mActivePasswordLength);
   1007             pw.print("  mFailedPasswordAttempts="); pw.println(mFailedPasswordAttempts);
   1008             pw.print("  mPasswordOwner="); pw.println(mPasswordOwner);
   1009         }
   1010     }
   1011 }
   1012