Merge "Replace com.android.internal.util.Preconditions.checkNotNull with java.util.Objects.requireNonNull"
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index 27db294..4cc5a67 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -22,6 +22,7 @@
 <resources>
     <!-- SystemUI Services: The classes of the stuff to start. -->
     <string-array name="config_systemUIServiceComponents" translatable="false">
+        <item>com.android.systemui.util.NotificationChannels</item>
         <item>com.android.systemui.volume.VolumeUI</item>
         <item>com.android.systemui.stackdivider.Divider</item>
         <item>com.android.systemui.statusbar.tv.TvStatusBar</item>
diff --git a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index e5292a0..f3d60f5 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -225,11 +225,13 @@
             builder.setIsPreInstalled(isSystemApp(packageName));
 
             AppInstallMetadata appInstallMetadata = builder.build();
+            Map<String, String> allowedInstallers = getAllowedInstallers(packageInfo);
 
-            Slog.i(TAG, "To be verified: " + appInstallMetadata);
+            Slog.i(
+                    TAG,
+                    "To be verified: " + appInstallMetadata + " installers " + allowedInstallers);
             IntegrityCheckResult result =
-                    mEvaluationEngine.evaluate(
-                            appInstallMetadata, getAllowedInstallers(packageInfo));
+                    mEvaluationEngine.evaluate(appInstallMetadata, allowedInstallers);
             Slog.i(
                     TAG,
                     "Integrity check result: "
@@ -371,7 +373,7 @@
                     String[] packageAndCert =
                             packageCertPair.split(INSTALLER_PACKAGE_CERT_DELIMITER);
                     if (packageAndCert.length == 2) {
-                        String packageName = packageAndCert[0];
+                        String packageName = getPackageNameNormalized(packageAndCert[0]);
                         String cert = packageAndCert[1];
                         packageCertMap.put(packageName, cert);
                     }
@@ -379,21 +381,9 @@
             }
         }
 
-        Slog.i("DEBUG", "allowed installers map " + packageCertMap);
         return packageCertMap;
     }
 
-    private boolean getPreInstalled(String packageName) {
-        try {
-            PackageInfo existingPackageInfo =
-                    mContext.getPackageManager().getPackageInfo(packageName, 0);
-            return existingPackageInfo.applicationInfo != null
-                    && existingPackageInfo.applicationInfo.isSystemApp();
-        } catch (PackageManager.NameNotFoundException e) {
-            return false;
-        }
-    }
-
     private static Signature getSignature(@NonNull PackageInfo packageInfo) {
         if (packageInfo.signatures == null || packageInfo.signatures.length < 1) {
             throw new IllegalArgumentException("Package signature not found in " + packageInfo);
@@ -463,7 +453,8 @@
         PackageInfo basePackageInfo =
                 mContext.getPackageManager()
                         .getPackageArchiveInfo(
-                                baseFile.getAbsolutePath(), PackageManager.GET_SIGNATURES);
+                                baseFile.getAbsolutePath(),
+                                PackageManager.GET_SIGNATURES | PackageManager.GET_META_DATA);
 
         if (basePackageInfo == null) {
             for (File apkFile : multiApkDirectory.listFiles()) {
@@ -477,7 +468,8 @@
                         mContext.getPackageManager()
                                 .getPackageArchiveInfo(
                                         apkFile.getAbsolutePath(),
-                                        PackageManager.GET_SIGNING_CERTIFICATES);
+                                        PackageManager.GET_SIGNING_CERTIFICATES
+                                                | PackageManager.GET_META_DATA);
                 if (basePackageInfo != null) {
                     Slog.i(TAG, "Found package info from " + apkFile);
                     break;
diff --git a/services/core/java/com/android/server/integrity/IntegrityFileManager.java b/services/core/java/com/android/server/integrity/IntegrityFileManager.java
index bdf0279..e224724 100644
--- a/services/core/java/com/android/server/integrity/IntegrityFileManager.java
+++ b/services/core/java/com/android/server/integrity/IntegrityFileManager.java
@@ -24,14 +24,14 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.integrity.model.RuleMetadata;
-import com.android.server.integrity.parser.RuleBinaryParser;
 import com.android.server.integrity.parser.RuleMetadataParser;
 import com.android.server.integrity.parser.RuleParseException;
 import com.android.server.integrity.parser.RuleParser;
-import com.android.server.integrity.serializer.RuleBinarySerializer;
+import com.android.server.integrity.parser.RuleXmlParser;
 import com.android.server.integrity.serializer.RuleMetadataSerializer;
 import com.android.server.integrity.serializer.RuleSerializeException;
 import com.android.server.integrity.serializer.RuleSerializer;
+import com.android.server.integrity.serializer.RuleXmlSerializer;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -75,8 +75,8 @@
 
     private IntegrityFileManager() {
         this(
-                new RuleBinaryParser(),
-                new RuleBinarySerializer(),
+                new RuleXmlParser(),
+                new RuleXmlSerializer(),
                 Environment.getDataSystemDirectory());
     }
 
diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
index 0ea6efc..07eacbf 100644
--- a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
+++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
@@ -17,15 +17,21 @@
 package com.android.server.integrity.engine;
 
 import android.content.integrity.AppInstallMetadata;
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Formula;
 import android.content.integrity.Rule;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.integrity.IntegrityFileManager;
 import com.android.server.integrity.model.IntegrityCheckResult;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 /**
  * The engine used to evaluate rules against app installs.
@@ -42,7 +48,8 @@
 
     private final IntegrityFileManager mIntegrityFileManager;
 
-    private RuleEvaluationEngine(IntegrityFileManager integrityFileManager) {
+    @VisibleForTesting
+    RuleEvaluationEngine(IntegrityFileManager integrityFileManager) {
         mIntegrityFileManager = integrityFileManager;
     }
 
@@ -64,6 +71,7 @@
     public IntegrityCheckResult evaluate(
             AppInstallMetadata appInstallMetadata, Map<String, String> allowedInstallers) {
         List<Rule> rules = loadRules(appInstallMetadata);
+        allowedInstallersRule(allowedInstallers).ifPresent(rules::add);
         return RuleEvaluator.evaluateRules(rules, appInstallMetadata);
     }
 
@@ -75,4 +83,42 @@
             return new ArrayList<>();
         }
     }
+
+    private static Optional<Rule> allowedInstallersRule(Map<String, String> allowedInstallers) {
+        if (allowedInstallers.isEmpty()) {
+            return Optional.empty();
+        }
+
+        List<Formula> formulas = new ArrayList<>(allowedInstallers.size());
+        allowedInstallers.forEach(
+                (installer, cert) -> {
+                    formulas.add(allowedInstallerFormula(installer, cert));
+                });
+
+        // We need this special case since OR-formulas require at least two operands.
+        Formula allInstallersFormula =
+                formulas.size() == 1
+                        ? formulas.get(0)
+                        : new CompoundFormula(CompoundFormula.OR, formulas);
+
+        return Optional.of(
+                new Rule(
+                        new CompoundFormula(
+                                CompoundFormula.NOT, Arrays.asList(allInstallersFormula)),
+                        Rule.DENY));
+    }
+
+    private static Formula allowedInstallerFormula(String installer, String cert) {
+        return new CompoundFormula(
+                CompoundFormula.AND,
+                Arrays.asList(
+                        new AtomicFormula.StringAtomicFormula(
+                                AtomicFormula.INSTALLER_NAME,
+                                installer,
+                                /* isHashedValue= */ false),
+                        new AtomicFormula.StringAtomicFormula(
+                                AtomicFormula.INSTALLER_CERTIFICATE,
+                                cert,
+                                /* isHashedValue= */ false)));
+    }
 }
diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java
index ee51d4f..b1c20d2 100644
--- a/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java
+++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java
@@ -21,9 +21,6 @@
 
 import android.annotation.NonNull;
 import android.content.integrity.AppInstallMetadata;
-import android.content.integrity.AtomicFormula;
-import android.content.integrity.CompoundFormula;
-import android.content.integrity.Formula;
 import android.content.integrity.Rule;
 import android.util.Slog;
 
@@ -56,8 +53,7 @@
             List<Rule> rules, AppInstallMetadata appInstallMetadata) {
         List<Rule> matchedRules = new ArrayList<>();
         for (Rule rule : rules) {
-            if (isConjunctionOfFormulas(rule.getFormula())
-                    && rule.getFormula().isSatisfied(appInstallMetadata)) {
+            if (rule.getFormula().isSatisfied(appInstallMetadata)) {
                 matchedRules.add(rule);
             }
         }
@@ -81,25 +77,4 @@
         }
         return denied ? IntegrityCheckResult.deny(denyRule) : IntegrityCheckResult.allow();
     }
-
-    private static boolean isConjunctionOfFormulas(Formula formula) {
-        if (formula == null) {
-            return false;
-        }
-        if (isAtomicFormula(formula)) {
-            return true;
-        }
-        CompoundFormula compoundFormula = (CompoundFormula) formula;
-        return compoundFormula.getConnector() == CompoundFormula.AND
-                && compoundFormula.getFormulas().stream().allMatch(RuleEvaluator::isAtomicFormula);
-    }
-
-    private static boolean isAtomicFormula(Formula formula) {
-        if (formula instanceof AtomicFormula) {
-            return true;
-        }
-        CompoundFormula compoundFormula = (CompoundFormula) formula;
-        return compoundFormula.getConnector() == CompoundFormula.NOT
-                && compoundFormula.getFormulas().get(0) instanceof AtomicFormula;
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
new file mode 100644
index 0000000..d386487
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluationEngineTest.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2019 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.integrity.engine;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import android.content.integrity.AppInstallMetadata;
+import android.content.integrity.Rule;
+
+import com.android.server.integrity.IntegrityFileManager;
+import com.android.server.integrity.model.IntegrityCheckResult;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+@RunWith(JUnit4.class)
+public class RuleEvaluationEngineTest {
+
+    private static final String INSTALLER_1 = "installer1";
+    private static final String INSTALLER_1_CERT = "installer1_cert";
+    private static final String INSTALLER_2 = "installer2";
+    private static final String INSTALLER_2_CERT = "installer2_cert";
+
+    private static final String RANDOM_INSTALLER = "random";
+    private static final String RANDOM_INSTALLER_CERT = "random_cert";
+
+    @Mock private IntegrityFileManager mIntegrityFileManager;
+
+    private RuleEvaluationEngine mEngine;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mEngine = new RuleEvaluationEngine(mIntegrityFileManager);
+
+        when(mIntegrityFileManager.readRules(any())).thenReturn(new ArrayList<>());
+    }
+
+    @Test
+    public void testAllowedInstallers_empty() {
+        Map<String, String> allowedInstallers = Collections.emptyMap();
+
+        assertEquals(
+                IntegrityCheckResult.Effect.ALLOW,
+                mEngine.evaluate(
+                                getAppInstallMetadataBuilder()
+                                        .setInstallerName(INSTALLER_1)
+                                        .setInstallerCertificate(INSTALLER_1_CERT)
+                                        .build(),
+                                allowedInstallers)
+                        .getEffect());
+        assertEquals(
+                IntegrityCheckResult.Effect.ALLOW,
+                mEngine.evaluate(
+                                getAppInstallMetadataBuilder()
+                                        .setInstallerName(INSTALLER_2)
+                                        .setInstallerCertificate(INSTALLER_2_CERT)
+                                        .build(),
+                                allowedInstallers)
+                        .getEffect());
+        assertEquals(
+                IntegrityCheckResult.Effect.ALLOW,
+                mEngine.evaluate(
+                                getAppInstallMetadataBuilder()
+                                        .setInstallerName(RANDOM_INSTALLER)
+                                        .setInstallerCertificate(RANDOM_INSTALLER_CERT)
+                                        .build(),
+                                allowedInstallers)
+                        .getEffect());
+    }
+
+    @Test
+    public void testAllowedInstallers_oneElement() {
+        Map<String, String> allowedInstallers =
+                Collections.singletonMap(INSTALLER_1, INSTALLER_1_CERT);
+
+        assertEquals(
+                IntegrityCheckResult.Effect.ALLOW,
+                mEngine.evaluate(
+                                getAppInstallMetadataBuilder()
+                                        .setInstallerName(INSTALLER_1)
+                                        .setInstallerCertificate(INSTALLER_1_CERT)
+                                        .build(),
+                                allowedInstallers)
+                        .getEffect());
+        assertEquals(
+                IntegrityCheckResult.Effect.DENY,
+                mEngine.evaluate(
+                                getAppInstallMetadataBuilder()
+                                        .setInstallerName(RANDOM_INSTALLER)
+                                        .setInstallerCertificate(INSTALLER_1_CERT)
+                                        .build(),
+                                allowedInstallers)
+                        .getEffect());
+        assertEquals(
+                IntegrityCheckResult.Effect.DENY,
+                mEngine.evaluate(
+                                getAppInstallMetadataBuilder()
+                                        .setInstallerName(INSTALLER_1)
+                                        .setInstallerCertificate(RANDOM_INSTALLER_CERT)
+                                        .build(),
+                                allowedInstallers)
+                        .getEffect());
+        assertEquals(
+                IntegrityCheckResult.Effect.DENY,
+                mEngine.evaluate(
+                                getAppInstallMetadataBuilder()
+                                        .setInstallerName(RANDOM_INSTALLER)
+                                        .setInstallerCertificate(RANDOM_INSTALLER_CERT)
+                                        .build(),
+                                allowedInstallers)
+                        .getEffect());
+    }
+
+    @Test
+    public void testAllowedInstallers_multipleElement() {
+        List<Rule> rules = new ArrayList<>();
+        Map<String, String> allowedInstallers = new HashMap<>(2);
+        allowedInstallers.put(INSTALLER_1, INSTALLER_1_CERT);
+        allowedInstallers.put(INSTALLER_2, INSTALLER_2_CERT);
+
+        assertEquals(
+                IntegrityCheckResult.Effect.ALLOW,
+                mEngine.evaluate(
+                                getAppInstallMetadataBuilder()
+                                        .setInstallerName(INSTALLER_1)
+                                        .setInstallerCertificate(INSTALLER_1_CERT)
+                                        .build(),
+                                allowedInstallers)
+                        .getEffect());
+        assertEquals(
+                IntegrityCheckResult.Effect.ALLOW,
+                mEngine.evaluate(
+                                getAppInstallMetadataBuilder()
+                                        .setInstallerName(INSTALLER_2)
+                                        .setInstallerCertificate(INSTALLER_2_CERT)
+                                        .build(),
+                                allowedInstallers)
+                        .getEffect());
+        assertEquals(
+                IntegrityCheckResult.Effect.DENY,
+                mEngine.evaluate(
+                                getAppInstallMetadataBuilder()
+                                        .setInstallerName(INSTALLER_1)
+                                        .setInstallerCertificate(INSTALLER_2_CERT)
+                                        .build(),
+                                allowedInstallers)
+                        .getEffect());
+        assertEquals(
+                IntegrityCheckResult.Effect.DENY,
+                mEngine.evaluate(
+                                getAppInstallMetadataBuilder()
+                                        .setInstallerName(INSTALLER_2)
+                                        .setInstallerCertificate(INSTALLER_1_CERT)
+                                        .build(),
+                                allowedInstallers)
+                        .getEffect());
+    }
+
+    /** Returns a builder with all fields filled with some dummy data. */
+    private AppInstallMetadata.Builder getAppInstallMetadataBuilder() {
+        return new AppInstallMetadata.Builder()
+                .setPackageName("abc")
+                .setAppCertificate("abc")
+                .setInstallerCertificate("abc")
+                .setInstallerName("abc")
+                .setVersionCode(-1)
+                .setIsPreInstalled(true);
+    }
+}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 96d2df1..68b16f3 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -74,13 +74,13 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.ISoundTriggerService;
-import com.android.internal.util.Preconditions;
 import com.android.server.SystemService;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Map;
+import java.util.Objects;
 import java.util.TreeMap;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
@@ -429,9 +429,9 @@
         @Override
         public int startRecognitionForService(ParcelUuid soundModelId, Bundle params,
             ComponentName detectionService, SoundTrigger.RecognitionConfig config) {
-            Preconditions.checkNotNull(soundModelId);
-            Preconditions.checkNotNull(detectionService);
-            Preconditions.checkNotNull(config);
+            Objects.requireNonNull(soundModelId);
+            Objects.requireNonNull(detectionService);
+            Objects.requireNonNull(config);
 
             enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER);
 
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 404346f..e9db31b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -76,7 +76,6 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
-import com.android.internal.util.Preconditions;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -89,6 +88,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 
 /**
@@ -117,11 +117,11 @@
         mResolver = context.getContentResolver();
         mDbHelper = new DatabaseHelper(context);
         mServiceStub = new VoiceInteractionManagerServiceStub();
-        mAmInternal = Preconditions.checkNotNull(
+        mAmInternal = Objects.requireNonNull(
                 LocalServices.getService(ActivityManagerInternal.class));
-        mAtmInternal = Preconditions.checkNotNull(
+        mAtmInternal = Objects.requireNonNull(
                 LocalServices.getService(ActivityTaskManagerInternal.class));
-        mUserManagerInternal = Preconditions.checkNotNull(
+        mUserManagerInternal = Objects.requireNonNull(
                 LocalServices.getService(UserManagerInternal.class));
 
         PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService(
@@ -149,7 +149,7 @@
     @Override
     public void onBootPhase(int phase) {
         if (PHASE_SYSTEM_SERVICES_READY == phase) {
-            mShortcutServiceInternal = Preconditions.checkNotNull(
+            mShortcutServiceInternal = Objects.requireNonNull(
                     LocalServices.getService(ShortcutServiceInternal.class));
             mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class);
         } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {