diff options
Diffstat (limited to 'services/core/java')
6 files changed, 218 insertions, 60 deletions
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java index f222dba..2eb8797 100644 --- a/services/core/java/com/android/server/content/SyncManager.java +++ b/services/core/java/com/android/server/content/SyncManager.java @@ -801,7 +801,7 @@ public class SyncManager { for (String authority : syncableAuthorities) { int isSyncable = getIsSyncable(account.account, account.userId, authority); - if (isSyncable == 0) { + if (isSyncable == AuthorityInfo.NOT_SYNCABLE) { continue; } final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo; @@ -813,8 +813,9 @@ public class SyncManager { final boolean allowParallelSyncs = syncAdapterInfo.type.allowParallelSyncs(); final boolean isAlwaysSyncable = syncAdapterInfo.type.isAlwaysSyncable(); if (isSyncable < 0 && isAlwaysSyncable) { - mSyncStorageEngine.setIsSyncable(account.account, account.userId, authority, 1); - isSyncable = 1; + mSyncStorageEngine.setIsSyncable( + account.account, account.userId, authority, AuthorityInfo.SYNCABLE); + isSyncable = AuthorityInfo.SYNCABLE; } if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) { continue; diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java index d68b615..cca0c16 100644 --- a/services/core/java/com/android/server/content/SyncStorageEngine.java +++ b/services/core/java/com/android/server/content/SyncStorageEngine.java @@ -301,6 +301,30 @@ public class SyncStorageEngine extends Handler { } public static class AuthorityInfo { + // Legal values of getIsSyncable + /** + * Default state for a newly installed adapter. An uninitialized adapter will receive an + * initialization sync which are governed by a different set of rules to that of regular + * syncs. + */ + public static final int NOT_INITIALIZED = -1; + /** + * The adapter will not receive any syncs. This is behaviourally equivalent to + * setSyncAutomatically -> false. However setSyncAutomatically is surfaced to the user + * while this is generally meant to be controlled by the developer. + */ + public static final int NOT_SYNCABLE = 0; + /** + * The adapter is initialized and functioning. This is the normal state for an adapter. + */ + public static final int SYNCABLE = 1; + /** + * The adapter is syncable but still requires an initialization sync. For example an adapter + * than has been restored from a previous device will be in this state. Not meant for + * external use. + */ + public static final int SYNCABLE_NOT_INITIALIZED = 2; + final EndPoint target; final int ident; boolean enabled; @@ -349,12 +373,11 @@ public class SyncStorageEngine extends Handler { } private void defaultInitialisation() { - syncable = -1; // default to "unknown" + syncable = NOT_INITIALIZED; // default to "unknown" backoffTime = -1; // if < 0 then we aren't in backoff mode backoffDelay = -1; // if < 0 then we aren't in backoff mode PeriodicSync defaultSync; - // Old version is one sync a day. Empty bundle gets replaced by any addPeriodicSync() - // call. + // Old version is one sync a day. if (target.target_provider) { defaultSync = new PeriodicSync(target.account, target.provider, @@ -663,6 +686,12 @@ public class SyncStorageEngine extends Handler { } return; } + // If the adapter was syncable but missing its initialization sync, set it to + // uninitialized now. This is to give it a chance to run any one-time initialization + // logic. + if (sync && authority.syncable == AuthorityInfo.SYNCABLE_NOT_INITIALIZED) { + authority.syncable = AuthorityInfo.NOT_INITIALIZED; + } authority.enabled = sync; writeAccountInfoLocked(); } @@ -682,7 +711,7 @@ public class SyncStorageEngine extends Handler { new EndPoint(account, providerName, userId), "get authority syncable"); if (authority == null) { - return -1; + return AuthorityInfo.NOT_INITIALIZED; } return authority.syncable; } @@ -696,7 +725,7 @@ public class SyncStorageEngine extends Handler { return authorityInfo.syncable; } } - return -1; + return AuthorityInfo.NOT_INITIALIZED; } } @@ -720,7 +749,8 @@ public class SyncStorageEngine extends Handler { } public void setIsTargetServiceActive(ComponentName cname, int userId, boolean active) { - setSyncableStateForEndPoint(new EndPoint(cname, userId), active ? 1 : 0); + setSyncableStateForEndPoint(new EndPoint(cname, userId), active ? + AuthorityInfo.SYNCABLE : AuthorityInfo.NOT_SYNCABLE); } /** @@ -733,10 +763,8 @@ public class SyncStorageEngine extends Handler { AuthorityInfo aInfo; synchronized (mAuthorities) { aInfo = getOrCreateAuthorityLocked(target, -1, false); - if (syncable > 1) { - syncable = 1; - } else if (syncable < -1) { - syncable = -1; + if (syncable < AuthorityInfo.NOT_INITIALIZED) { + syncable = AuthorityInfo.NOT_INITIALIZED; } if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.d(TAG, "setIsSyncable: " + aInfo.toString() + " -> " + syncable); @@ -750,7 +778,7 @@ public class SyncStorageEngine extends Handler { aInfo.syncable = syncable; writeAccountInfoLocked(); } - if (syncable > 0) { + if (syncable == AuthorityInfo.SYNCABLE) { requestSync(aInfo, SyncOperation.REASON_IS_SYNCABLE, new Bundle()); } reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS); @@ -2012,7 +2040,7 @@ public class SyncStorageEngine extends Handler { int userId = user == null ? 0 : Integer.parseInt(user); if (accountType == null && packageName == null) { accountType = "com.google"; - syncable = "unknown"; + syncable = String.valueOf(AuthorityInfo.NOT_INITIALIZED); } authority = mAuthorities.get(id); if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) { @@ -2052,11 +2080,19 @@ public class SyncStorageEngine extends Handler { } if (authority != null) { authority.enabled = enabled == null || Boolean.parseBoolean(enabled); - if ("unknown".equals(syncable)) { - authority.syncable = -1; - } else { - authority.syncable = - (syncable == null || Boolean.parseBoolean(syncable)) ? 1 : 0; + try { + authority.syncable = (syncable == null) ? + AuthorityInfo.NOT_INITIALIZED : Integer.parseInt(syncable); + } catch (NumberFormatException e) { + // On L we stored this as {"unknown", "true", "false"} so fall back to this + // format. + if ("unknown".equals(syncable)) { + authority.syncable = AuthorityInfo.NOT_INITIALIZED; + } else { + authority.syncable = Boolean.parseBoolean(syncable) ? + AuthorityInfo.SYNCABLE : AuthorityInfo.NOT_SYNCABLE; + } + } } else { Log.w(TAG, "Failure adding authority: account=" @@ -2190,11 +2226,7 @@ public class SyncStorageEngine extends Handler { out.attribute(null, "package", info.service.getPackageName()); out.attribute(null, "class", info.service.getClassName()); } - if (authority.syncable < 0) { - out.attribute(null, "syncable", "unknown"); - } else { - out.attribute(null, "syncable", Boolean.toString(authority.syncable != 0)); - } + out.attribute(null, "syncable", Integer.toString(authority.syncable)); for (PeriodicSync periodicSync : authority.periodicSyncs) { out.startTag(null, "periodicSync"); out.attribute(null, "period", Long.toString(periodicSync.period)); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index 77b800e..7999321 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -246,6 +246,8 @@ abstract class HdmiCecLocalDevice { return handleRequestActiveSource(message); case Constants.MESSAGE_GET_MENU_LANGUAGE: return handleGetMenuLanguage(message); + case Constants.MESSAGE_SET_MENU_LANGUAGE: + return handleSetMenuLanguage(message); case Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS: return handleGivePhysicalAddress(); case Constants.MESSAGE_GIVE_OSD_NAME: @@ -377,6 +379,14 @@ abstract class HdmiCecLocalDevice { } @ServiceThreadOnly + protected boolean handleSetMenuLanguage(HdmiCecMessage message) { + assertRunOnServiceThread(); + Slog.w(TAG, "Only Playback device can handle <Set Menu Language>:" + message.toString()); + // 'return false' will cause to reply with <Feature Abort>. + return false; + } + + @ServiceThreadOnly protected boolean handleGiveOsdName(HdmiCecMessage message) { assertRunOnServiceThread(); // Note that since this method is called after logical address allocation is done, diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java index 30a9b43..493471b 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java @@ -26,9 +26,14 @@ import android.os.SystemProperties; import android.provider.Settings.Global; import android.util.Slog; +import com.android.internal.app.LocalePicker; +import com.android.internal.app.LocalePicker.LocaleInfo; import com.android.internal.util.IndentingPrintWriter; import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; +import java.io.UnsupportedEncodingException; +import java.util.List; + /** * Represent a logical device of type Playback residing in Android system. */ @@ -306,6 +311,35 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { return true; // Broadcast message. } + @ServiceThreadOnly + protected boolean handleSetMenuLanguage(HdmiCecMessage message) { + assertRunOnServiceThread(); + + try { + String iso3Language = new String(message.getParams(), 0, 3, "US-ASCII"); + + // Don't use Locale.getAvailableLocales() since it returns a locale + // which is not available on Settings. + final List<LocaleInfo> localeInfos = LocalePicker.getAllAssetLocales( + mService.getContext(), false); + for (LocaleInfo localeInfo : localeInfos) { + if (localeInfo.getLocale().getISO3Language().equals(iso3Language)) { + // WARNING: CEC adopts ISO/FDIS-2 for language code, while Android requires + // additional country variant to pinpoint the locale. This keeps the right + // locale from being chosen. 'eng' in the CEC command, for instance, + // will always be mapped to en-AU among other variants like en-US, en-GB, + // an en-IN, which may not be the expected one. + LocalePicker.updateLocale(localeInfo.getLocale()); + return true; + } + } + Slog.w(TAG, "Can't handle <Set Menu Language> of " + iso3Language); + return false; + } catch (UnsupportedEncodingException e) { + return false; + } + } + @Override @ServiceThreadOnly protected void sendStandby(int deviceId) { diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java index 1ee07a5..0de0c92 100644 --- a/services/core/java/com/android/server/pm/KeySetManagerService.java +++ b/services/core/java/com/android/server/pm/KeySetManagerService.java @@ -16,6 +16,9 @@ package com.android.server.pm; +import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK; + +import com.android.internal.util.Preconditions; import android.content.pm.PackageParser; import android.util.ArrayMap; import android.util.ArraySet; @@ -98,6 +101,7 @@ public class KeySetManagerService { mRefCount++; return; } + public long decrRefCountLPw() { mRefCount--; return mRefCount; @@ -168,25 +172,82 @@ public class KeySetManagerService { } /** + * addScannedPackageLPw directly modifies the package metadata in pm.Settings + * at a point of no-return. We need to make sure that the scanned package does + * not contain bad keyset meta-data that could generate an incorrect + * PackageSetting. Verify that there is a signing keyset, there are no issues + * with null objects, and the upgrade and defined keysets match. + * + * Returns true if the package can safely be added to the keyset metadata. + */ + public void assertScannedPackageValid(PackageParser.Package pkg) + throws PackageManagerException { + if (pkg == null || pkg.packageName == null) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Passed invalid package to keyset validation."); + } + ArraySet<PublicKey> signingKeys = pkg.mSigningKeys; + if (signingKeys == null || !(signingKeys.size() > 0) || signingKeys.contains(null)) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Package has invalid signing-key-set."); + } + ArrayMap<String, ArraySet<PublicKey>> definedMapping = pkg.mKeySetMapping; + if (definedMapping != null) { + if (definedMapping.containsKey(null) || definedMapping.containsValue(null)) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Package has null defined key set."); + } + int defMapSize = definedMapping.size(); + for (int i = 0; i < defMapSize; i++) { + if (!(definedMapping.valueAt(i).size() > 0) + || definedMapping.valueAt(i).contains(null)) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Package has null/no public keys for defined key-sets."); + } + } + } + ArraySet<String> upgradeAliases = pkg.mUpgradeKeySets; + if (upgradeAliases != null) { + if (definedMapping == null || !(definedMapping.keySet().containsAll(upgradeAliases))) { + throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, + "Package has upgrade-key-sets without corresponding definitions."); + } + } + } + + public void addScannedPackageLPw(PackageParser.Package pkg) { + Preconditions.checkNotNull(pkg, "Attempted to add null pkg to ksms."); + Preconditions.checkNotNull(pkg.packageName, "Attempted to add null pkg to ksms."); + PackageSetting ps = mPackages.get(pkg.packageName); + Preconditions.checkNotNull(ps, "pkg: " + pkg.packageName + + "does not have a corresponding entry in mPackages."); + addSigningKeySetToPackageLPw(ps, pkg.mSigningKeys); + if (pkg.mKeySetMapping != null) { + addDefinedKeySetsToPackageLPw(ps, pkg.mKeySetMapping); + if (pkg.mUpgradeKeySets != null) { + addUpgradeKeySetsToPackageLPw(ps, pkg.mUpgradeKeySets); + } + } + } + + /** * Informs the system that the given package was signed by the provided KeySet. */ - public void addSigningKeySetToPackageLPw(String packageName, + void addSigningKeySetToPackageLPw(PackageSetting pkg, ArraySet<PublicKey> signingKeys) { /* check existing keyset for reuse or removal */ - PackageSetting pkg = mPackages.get(packageName); long signingKeySetId = pkg.keySetData.getProperSigningKeySet(); if (signingKeySetId != PackageKeySetData.KEYSET_UNASSIGNED) { ArraySet<PublicKey> existingKeys = getPublicKeysFromKeySetLPr(signingKeySetId); - if (existingKeys.equals(signingKeys)) { + if (existingKeys != null && existingKeys.equals(signingKeys)) { /* no change in signing keys, leave PackageSetting alone */ return; } else { /* old keyset no longer valid, remove ref */ - KeySetHandle ksh = mKeySets.get(signingKeySetId); decrementKeySetLPw(signingKeySetId); } } @@ -212,13 +273,12 @@ public class KeySetManagerService { return KEYSET_NOT_FOUND; } - /* + /** * Inform the system that the given package defines the given KeySets. * Remove any KeySets the package no longer defines. */ - public void addDefinedKeySetsToPackageLPw(String packageName, + void addDefinedKeySetsToPackageLPw(PackageSetting pkg, ArrayMap<String, ArraySet<PublicKey>> definedMapping) { - PackageSetting pkg = mPackages.get(packageName); ArrayMap<String, Long> prevDefinedKeySets = pkg.keySetData.getAliases(); /* add all of the newly defined KeySets */ @@ -227,7 +287,7 @@ public class KeySetManagerService { for (int i = 0; i < defMapSize; i++) { String alias = definedMapping.keyAt(i); ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i); - if (alias != null && pubKeys != null && pubKeys.size() > 0) { + if (alias != null && pubKeys != null || pubKeys.size() > 0) { KeySetHandle ks = addKeySetLPw(pubKeys); newKeySetAliases.put(alias, ks.getId()); } @@ -250,9 +310,8 @@ public class KeySetManagerService { * alias in its manifest to be an upgradeKeySet. This must be called * after all of the defined KeySets have been added. */ - public void addUpgradeKeySetsToPackageLPw(String packageName, - ArraySet<String> upgradeAliases) { - PackageSetting pkg = mPackages.get(packageName); + void addUpgradeKeySetsToPackageLPw(PackageSetting pkg, + ArraySet<String> upgradeAliases) { final int uaSize = upgradeAliases.size(); for (int i = 0; i < uaSize; i++) { pkg.keySetData.addUpgradeKeySet(upgradeAliases.valueAt(i)); @@ -290,11 +349,11 @@ public class KeySetManagerService { * identify a {@link KeySetHandle}. */ public ArraySet<PublicKey> getPublicKeysFromKeySetLPr(long id) { - if(mKeySetMapping.get(id) == null) { + ArraySet<Long> pkIds = mKeySetMapping.get(id); + if (pkIds == null) { return null; } ArraySet<PublicKey> mPubKeys = new ArraySet<PublicKey>(); - ArraySet<Long> pkIds = mKeySetMapping.get(id); final int pkSize = pkIds.size(); for (int i = 0; i < pkSize; i++) { mPubKeys.add(mPublicKeys.get(pkIds.valueAt(i)).getKey()); @@ -376,6 +435,10 @@ public class KeySetManagerService { */ private void decrementKeySetLPw(long id) { KeySetHandle ks = mKeySets.get(id); + if (ks == null) { + /* nothing to do */ + return; + } if (ks.decrRefCountLPw() <= 0) { ArraySet<Long> pubKeys = mKeySetMapping.get(id); final int pkSize = pubKeys.size(); @@ -385,7 +448,6 @@ public class KeySetManagerService { mKeySets.delete(id); mKeySetMapping.delete(id); } - return; } /* @@ -394,16 +456,20 @@ public class KeySetManagerService { */ private void decrementPublicKeyLPw(long id) { PublicKeyHandle pk = mPublicKeys.get(id); + if (pk == null) { + /* nothing to do */ + return; + } if (pk.decrRefCountLPw() <= 0) { mPublicKeys.delete(id); } - return; } /** * Adds the given PublicKey to the system, deduping as it goes. */ private long addPublicKeyLPw(PublicKey key) { + Preconditions.checkNotNull(key, "Cannot add null public key!"); long id = getIdForPublicKeyLPr(key); if (id != PUBLIC_KEY_NOT_FOUND) { @@ -473,6 +539,8 @@ public class KeySetManagerService { /* remove refs from common keysets and public keys */ PackageSetting pkg = mPackages.get(packageName); + Preconditions.checkNotNull(pkg, "pkg name: " + packageName + + "does not have a corresponding entry in mPackages."); long signingKeySetId = pkg.keySetData.getProperSigningKeySet(); decrementKeySetLPw(signingKeySetId); ArrayMap<String, Long> definedKeySets = pkg.keySetData.getAliases(); @@ -715,16 +783,36 @@ public class KeySetManagerService { final int numRefCounts = keySetRefCounts.size(); for (int i = 0; i < numRefCounts; i++) { KeySetHandle ks = mKeySets.get(keySetRefCounts.keyAt(i)); + if (ks == null) { + /* something went terribly wrong and we have references to a non-existent key-set */ + Slog.wtf(TAG, "Encountered non-existent key-set reference when reading settings"); + continue; + } ks.setRefCountLPw(keySetRefCounts.valueAt(i)); } + /* + * In case something went terribly wrong and we have keysets with no associated packges + * that refer to them, record the orphaned keyset ids, and remove them using + * decrementKeySetLPw() after all keyset references have been set so that the associtaed + * public keys have the appropriate references from all keysets. + */ + ArraySet<Long> orphanedKeySets = new ArraySet<Long>(); final int numKeySets = mKeySets.size(); for (int i = 0; i < numKeySets; i++) { + if (mKeySets.valueAt(i).getRefCountLPr() == 0) { + Slog.wtf(TAG, "Encountered key-set w/out package references when reading settings"); + orphanedKeySets.add(mKeySets.keyAt(i)); + } ArraySet<Long> pubKeys = mKeySetMapping.valueAt(i); final int pkSize = pubKeys.size(); for (int j = 0; j < pkSize; j++) { mPublicKeys.get(pubKeys.valueAt(j)).incrRefCountLPw(); } } + final int numOrphans = orphanedKeySets.size(); + for (int i = 0; i < numOrphans; i++) { + decrementKeySetLPw(orphanedKeySets.valueAt(i)); + } } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 548d93c..5b7dd70 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -5109,16 +5109,18 @@ public class PackageManagerService extends IPackageManager.Stub { && !isCompatSignatureUpdateNeeded(pkg) && !isRecoverSignatureUpdateNeeded(pkg)) { long mSigningKeySetId = ps.keySetData.getProperSigningKeySet(); + KeySetManagerService ksms = mSettings.mKeySetManagerService; + ArraySet<PublicKey> signingKs; + synchronized (mPackages) { + signingKs = ksms.getPublicKeysFromKeySetLPr(mSigningKeySetId); + } if (ps.signatures.mSignatures != null && ps.signatures.mSignatures.length != 0 - && mSigningKeySetId != PackageKeySetData.KEYSET_UNASSIGNED) { + && signingKs != null) { // Optimization: reuse the existing cached certificates // if the package appears to be unchanged. pkg.mSignatures = ps.signatures.mSignatures; - KeySetManagerService ksms = mSettings.mKeySetManagerService; - synchronized (mPackages) { - pkg.mSigningKeys = ksms.getPublicKeysFromKeySetLPr(mSigningKeySetId); - } + pkg.mSigningKeys = signingKs; return; } @@ -6590,6 +6592,10 @@ public class PackageManagerService extends IPackageManager.Stub { } } + // Make sure we're not adding any bogus keyset info + KeySetManagerService ksms = mSettings.mKeySetManagerService; + ksms.assertScannedPackageValid(pkg); + // writer synchronized (mPackages) { // We don't expect installation to fail beyond this point @@ -6626,20 +6632,7 @@ public class PackageManagerService extends IPackageManager.Stub { } // Add the package's KeySets to the global KeySetManagerService - KeySetManagerService ksms = mSettings.mKeySetManagerService; - try { - ksms.addSigningKeySetToPackageLPw(pkg.packageName, pkg.mSigningKeys); - if (pkg.mKeySetMapping != null) { - ksms.addDefinedKeySetsToPackageLPw(pkg.packageName, pkg.mKeySetMapping); - if (pkg.mUpgradeKeySets != null) { - ksms.addUpgradeKeySetsToPackageLPw(pkg.packageName, pkg.mUpgradeKeySets); - } - } - } catch (NullPointerException e) { - Slog.e(TAG, "Could not add KeySet to " + pkg.packageName, e); - } catch (IllegalArgumentException e) { - Slog.e(TAG, "Could not add KeySet to malformed package" + pkg.packageName, e); - } + ksms.addScannedPackageLPw(pkg); int N = pkg.providers.size(); StringBuilder r = null; @@ -11188,7 +11181,7 @@ public class PackageManagerService extends IPackageManager.Stub { KeySetManagerService ksms = mSettings.mKeySetManagerService; for (int i = 0; i < upgradeKeySets.length; i++) { Set<PublicKey> upgradeSet = ksms.getPublicKeysFromKeySetLPr(upgradeKeySets[i]); - if (newPkg.mSigningKeys.containsAll(upgradeSet)) { + if (upgradeSet != null && newPkg.mSigningKeys.containsAll(upgradeSet)) { return true; } } |
