Home | History | Annotate | Download | only in pm
      1 /*
      2  * Copyright (C) 2016 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 package com.android.server.pm;
     17 
     18 import android.annotation.NonNull;
     19 import android.annotation.UserIdInt;
     20 import android.content.pm.PackageInfo;
     21 import android.util.Slog;
     22 
     23 import com.android.server.backup.BackupUtils;
     24 
     25 import libcore.io.Base64;
     26 import libcore.util.HexEncoding;
     27 
     28 import org.xmlpull.v1.XmlPullParser;
     29 import org.xmlpull.v1.XmlPullParserException;
     30 import org.xmlpull.v1.XmlSerializer;
     31 
     32 import java.io.IOException;
     33 import java.io.PrintWriter;
     34 import java.util.ArrayList;
     35 
     36 /**
     37  * Package information used by {@link android.content.pm.ShortcutManager} for backup / restore.
     38  *
     39  * All methods should be guarded by {@code ShortcutService.mLock}.
     40  */
     41 class ShortcutPackageInfo {
     42     private static final String TAG = ShortcutService.TAG;
     43 
     44     static final String TAG_ROOT = "package-info";
     45     private static final String ATTR_VERSION = "version";
     46     private static final String ATTR_LAST_UPDATE_TIME = "last_udpate_time";
     47     private static final String ATTR_SHADOW = "shadow";
     48 
     49     private static final String TAG_SIGNATURE = "signature";
     50     private static final String ATTR_SIGNATURE_HASH = "hash";
     51 
     52     private static final int VERSION_UNKNOWN = -1;
     53 
     54     /**
     55      * When true, this package information was restored from the previous device, and the app hasn't
     56      * been installed yet.
     57      */
     58     private boolean mIsShadow;
     59     private int mVersionCode = VERSION_UNKNOWN;
     60     private long mLastUpdateTime;
     61     private ArrayList<byte[]> mSigHashes;
     62 
     63     private ShortcutPackageInfo(int versionCode, long lastUpdateTime,
     64             ArrayList<byte[]> sigHashes, boolean isShadow) {
     65         mVersionCode = versionCode;
     66         mLastUpdateTime = lastUpdateTime;
     67         mIsShadow = isShadow;
     68         mSigHashes = sigHashes;
     69     }
     70 
     71     public static ShortcutPackageInfo newEmpty() {
     72         return new ShortcutPackageInfo(VERSION_UNKNOWN, /* last update time =*/ 0,
     73                 new ArrayList<>(0), /* isShadow */ false);
     74     }
     75 
     76     public boolean isShadow() {
     77         return mIsShadow;
     78     }
     79 
     80     public void setShadow(boolean shadow) {
     81         mIsShadow = shadow;
     82     }
     83 
     84     public int getVersionCode() {
     85         return mVersionCode;
     86     }
     87 
     88     public long getLastUpdateTime() {
     89         return mLastUpdateTime;
     90     }
     91 
     92     public void updateVersionInfo(@NonNull PackageInfo pi) {
     93         if (pi != null) {
     94             mVersionCode = pi.versionCode;
     95             mLastUpdateTime = pi.lastUpdateTime;
     96         }
     97     }
     98 
     99     public boolean hasSignatures() {
    100         return mSigHashes.size() > 0;
    101     }
    102 
    103     public boolean canRestoreTo(ShortcutService s, PackageInfo target) {
    104         if (!s.shouldBackupApp(target)) {
    105             // "allowBackup" was true when backed up, but now false.
    106             Slog.w(TAG, "Can't restore: package no longer allows backup");
    107             return false;
    108         }
    109         if (target.versionCode < mVersionCode) {
    110             Slog.w(TAG, String.format(
    111                     "Can't restore: package current version %d < backed up version %d",
    112                     target.versionCode, mVersionCode));
    113             return false;
    114         }
    115         if (!BackupUtils.signaturesMatch(mSigHashes, target)) {
    116             Slog.w(TAG, "Can't restore: Package signature mismatch");
    117             return false;
    118         }
    119         return true;
    120     }
    121 
    122     public static ShortcutPackageInfo generateForInstalledPackage(
    123             ShortcutService s, String packageName, @UserIdInt int packageUserId) {
    124         final PackageInfo pi = s.getPackageInfoWithSignatures(packageName, packageUserId);
    125         if (pi.signatures == null || pi.signatures.length == 0) {
    126             Slog.e(TAG, "Can't get signatures: package=" + packageName);
    127             return null;
    128         }
    129         final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.versionCode, pi.lastUpdateTime,
    130                 BackupUtils.hashSignatureArray(pi.signatures), /* shadow=*/ false);
    131 
    132         return ret;
    133     }
    134 
    135     public void refresh(ShortcutService s, ShortcutPackageItem pkg) {
    136         if (mIsShadow) {
    137             s.wtf("Attempted to refresh package info for shadow package " + pkg.getPackageName()
    138                     + ", user=" + pkg.getOwnerUserId());
    139             return;
    140         }
    141         // Note use mUserId here, rather than userId.
    142         final PackageInfo pi = s.getPackageInfoWithSignatures(
    143                 pkg.getPackageName(), pkg.getPackageUserId());
    144         if (pi == null) {
    145             Slog.w(TAG, "Package not found: " + pkg.getPackageName());
    146             return;
    147         }
    148         mVersionCode = pi.versionCode;
    149         mLastUpdateTime = pi.lastUpdateTime;
    150         mSigHashes = BackupUtils.hashSignatureArray(pi.signatures);
    151     }
    152 
    153     public void saveToXml(XmlSerializer out) throws IOException {
    154 
    155         out.startTag(null, TAG_ROOT);
    156 
    157         ShortcutService.writeAttr(out, ATTR_VERSION, mVersionCode);
    158         ShortcutService.writeAttr(out, ATTR_LAST_UPDATE_TIME, mLastUpdateTime);
    159         ShortcutService.writeAttr(out, ATTR_SHADOW, mIsShadow);
    160 
    161         for (int i = 0; i < mSigHashes.size(); i++) {
    162             out.startTag(null, TAG_SIGNATURE);
    163             ShortcutService.writeAttr(out, ATTR_SIGNATURE_HASH, Base64.encode(mSigHashes.get(i)));
    164             out.endTag(null, TAG_SIGNATURE);
    165         }
    166         out.endTag(null, TAG_ROOT);
    167     }
    168 
    169     public void loadFromXml(XmlPullParser parser, boolean fromBackup)
    170             throws IOException, XmlPullParserException {
    171 
    172         final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION);
    173 
    174         final long lastUpdateTime = ShortcutService.parseLongAttribute(
    175                 parser, ATTR_LAST_UPDATE_TIME);
    176 
    177         // When restoring from backup, it's always shadow.
    178         final boolean shadow =
    179                 fromBackup || ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW);
    180 
    181         final ArrayList<byte[]> hashes = new ArrayList<>();
    182 
    183         final int outerDepth = parser.getDepth();
    184         int type;
    185         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    186                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
    187             if (type != XmlPullParser.START_TAG) {
    188                 continue;
    189             }
    190             final int depth = parser.getDepth();
    191             final String tag = parser.getName();
    192 
    193             if (depth == outerDepth + 1) {
    194                 switch (tag) {
    195                     case TAG_SIGNATURE: {
    196                         final String hash = ShortcutService.parseStringAttribute(
    197                                 parser, ATTR_SIGNATURE_HASH);
    198                         hashes.add(Base64.decode(hash.getBytes()));
    199                         continue;
    200                     }
    201                 }
    202             }
    203             ShortcutService.warnForInvalidTag(depth, tag);
    204         }
    205 
    206         // Successfully loaded; replace the feilds.
    207         mVersionCode = versionCode;
    208         mLastUpdateTime = lastUpdateTime;
    209         mIsShadow = shadow;
    210         mSigHashes = hashes;
    211     }
    212 
    213     public void dump(PrintWriter pw, String prefix) {
    214         pw.println();
    215 
    216         pw.print(prefix);
    217         pw.println("PackageInfo:");
    218 
    219         pw.print(prefix);
    220         pw.print("  IsShadow: ");
    221         pw.print(mIsShadow);
    222         pw.println();
    223 
    224         pw.print(prefix);
    225         pw.print("  Version: ");
    226         pw.print(mVersionCode);
    227         pw.println();
    228 
    229         pw.print(prefix);
    230         pw.print("  Last package update time: ");
    231         pw.print(mLastUpdateTime);
    232         pw.println();
    233 
    234         for (int i = 0; i < mSigHashes.size(); i++) {
    235             pw.print(prefix);
    236             pw.print("    ");
    237             pw.print("SigHash: ");
    238             pw.println(HexEncoding.encode(mSigHashes.get(i)));
    239         }
    240     }
    241 }
    242