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.content.pm.PackageInfo; 20 import android.content.pm.ShortcutInfo; 21 import android.util.Slog; 22 23 import com.android.internal.util.Preconditions; 24 25 import org.json.JSONException; 26 import org.json.JSONObject; 27 import org.xmlpull.v1.XmlPullParserException; 28 import org.xmlpull.v1.XmlSerializer; 29 30 import java.io.IOException; 31 32 /** 33 * All methods should be guarded by {@code #mShortcutUser.mService.mLock}. 34 */ 35 abstract class ShortcutPackageItem { 36 private static final String TAG = ShortcutService.TAG; 37 private static final String KEY_NAME = "name"; 38 39 private final int mPackageUserId; 40 private final String mPackageName; 41 42 private final ShortcutPackageInfo mPackageInfo; 43 44 protected ShortcutUser mShortcutUser; 45 ShortcutPackageItem(@onNull ShortcutUser shortcutUser, int packageUserId, @NonNull String packageName, @NonNull ShortcutPackageInfo packageInfo)46 protected ShortcutPackageItem(@NonNull ShortcutUser shortcutUser, 47 int packageUserId, @NonNull String packageName, 48 @NonNull ShortcutPackageInfo packageInfo) { 49 mShortcutUser = shortcutUser; 50 mPackageUserId = packageUserId; 51 mPackageName = Preconditions.checkStringNotEmpty(packageName); 52 mPackageInfo = Preconditions.checkNotNull(packageInfo); 53 } 54 55 /** 56 * Change the parent {@link ShortcutUser}. Need it in the restore code. 57 */ replaceUser(ShortcutUser user)58 public void replaceUser(ShortcutUser user) { 59 mShortcutUser = user; 60 } 61 getUser()62 public ShortcutUser getUser() { 63 return mShortcutUser; 64 } 65 66 /** 67 * ID of the user who actually has this package running on. For {@link ShortcutPackage}, 68 * this is the same thing as {@link #getOwnerUserId}, but if it's a {@link ShortcutLauncher} and 69 * {@link #getOwnerUserId} is of work profile, then this ID is of the primary user. 70 */ getPackageUserId()71 public int getPackageUserId() { 72 return mPackageUserId; 73 } 74 75 /** 76 * ID of the user who sees the shortcuts from this instance. 77 */ getOwnerUserId()78 public abstract int getOwnerUserId(); 79 80 @NonNull getPackageName()81 public String getPackageName() { 82 return mPackageName; 83 } 84 getPackageInfo()85 public ShortcutPackageInfo getPackageInfo() { 86 return mPackageInfo; 87 } 88 refreshPackageSignatureAndSave()89 public void refreshPackageSignatureAndSave() { 90 if (mPackageInfo.isShadow()) { 91 return; // Don't refresh for shadow user. 92 } 93 final ShortcutService s = mShortcutUser.mService; 94 mPackageInfo.refreshSignature(s, this); 95 s.scheduleSaveUser(getOwnerUserId()); 96 } 97 attemptToRestoreIfNeededAndSave()98 public void attemptToRestoreIfNeededAndSave() { 99 if (!mPackageInfo.isShadow()) { 100 return; // Already installed, nothing to do. 101 } 102 final ShortcutService s = mShortcutUser.mService; 103 if (!s.isPackageInstalled(mPackageName, mPackageUserId)) { 104 if (ShortcutService.DEBUG) { 105 Slog.d(TAG, String.format("Package still not installed: %s/u%d", 106 mPackageName, mPackageUserId)); 107 } 108 return; // Not installed, no need to restore yet. 109 } 110 int restoreBlockReason; 111 long currentVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN; 112 113 if (!mPackageInfo.hasSignatures()) { 114 s.wtf("Attempted to restore package " + mPackageName + "/u" + mPackageUserId 115 + " but signatures not found in the restore data."); 116 restoreBlockReason = ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH; 117 } else { 118 final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId); 119 currentVersionCode = pi.getLongVersionCode(); 120 restoreBlockReason = mPackageInfo.canRestoreTo(s, pi, canRestoreAnyVersion()); 121 } 122 123 if (ShortcutService.DEBUG) { 124 Slog.d(TAG, String.format("Restoring package: %s/u%d (version=%d) %s for u%d", 125 mPackageName, mPackageUserId, currentVersionCode, 126 ShortcutInfo.getDisabledReasonDebugString(restoreBlockReason), 127 getOwnerUserId())); 128 } 129 130 onRestored(restoreBlockReason); 131 132 // Either way, it's no longer a shadow. 133 mPackageInfo.setShadow(false); 134 135 s.scheduleSaveUser(mPackageUserId); 136 } 137 canRestoreAnyVersion()138 protected abstract boolean canRestoreAnyVersion(); 139 onRestored(int restoreBlockReason)140 protected abstract void onRestored(int restoreBlockReason); 141 saveToXml(@onNull XmlSerializer out, boolean forBackup)142 public abstract void saveToXml(@NonNull XmlSerializer out, boolean forBackup) 143 throws IOException, XmlPullParserException; 144 dumpCheckin(boolean clear)145 public JSONObject dumpCheckin(boolean clear) throws JSONException { 146 final JSONObject result = new JSONObject(); 147 result.put(KEY_NAME, mPackageName); 148 return result; 149 } 150 151 /** 152 * Verify various internal states. 153 */ verifyStates()154 public void verifyStates() { 155 } 156 } 157