1 /*
2  * Copyright (C) 2019 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 android.app;
18 
19 import android.compat.Compatibility;
20 import android.os.Process;
21 
22 import com.android.internal.compat.ChangeReporter;
23 
24 import java.util.Arrays;
25 
26 /**
27  * App process implementation of the {@link Compatibility} API.
28  *
29  * @hide
30  */
31 public final class AppCompatCallbacks implements Compatibility.BehaviorChangeDelegate {
32     private final long[] mDisabledChanges;
33     private final long[] mLoggableChanges;
34     private final ChangeReporter mChangeReporter;
35 
36     /**
37      * Install this class into the current process using the disabled and loggable changes lists.
38      *
39      * @param disabledChanges Set of compatibility changes that are disabled for this process.
40      * @param loggableChanges Set of compatibility changes that we want to log.
41      */
install(long[] disabledChanges, long[] loggableChanges)42     public static void install(long[] disabledChanges, long[] loggableChanges) {
43         Compatibility.setBehaviorChangeDelegate(
44                 new AppCompatCallbacks(disabledChanges, loggableChanges));
45     }
46 
AppCompatCallbacks(long[] disabledChanges, long[] loggableChanges)47     private AppCompatCallbacks(long[] disabledChanges, long[] loggableChanges) {
48         mDisabledChanges = Arrays.copyOf(disabledChanges, disabledChanges.length);
49         mLoggableChanges = Arrays.copyOf(loggableChanges, loggableChanges.length);
50         Arrays.sort(mDisabledChanges);
51         Arrays.sort(mLoggableChanges);
52         mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_APP_PROCESS);
53     }
54 
55     /**
56      * Helper to determine if a list contains a changeId.
57      *
58      * @param list to search through
59      * @param changeId for which to search in the list
60      * @return true if the given changeId is found in the provided array.
61      */
changeIdInChangeList(long[] list, long changeId)62     private boolean changeIdInChangeList(long[] list, long changeId) {
63         return Arrays.binarySearch(list, changeId) >= 0;
64     }
65 
onChangeReported(long changeId)66     public void onChangeReported(long changeId) {
67         boolean isLoggable = changeIdInChangeList(mLoggableChanges, changeId);
68         reportChange(changeId, ChangeReporter.STATE_LOGGED, isLoggable);
69     }
70 
isChangeEnabled(long changeId)71     public boolean isChangeEnabled(long changeId) {
72         boolean isEnabled = !changeIdInChangeList(mDisabledChanges, changeId);
73         boolean isLoggable = changeIdInChangeList(mLoggableChanges, changeId);
74         if (isEnabled) {
75             // Not present in the disabled changeId array
76             reportChange(changeId, ChangeReporter.STATE_ENABLED, isLoggable);
77             return true;
78         }
79         reportChange(changeId, ChangeReporter.STATE_DISABLED, isLoggable);
80         return false;
81     }
82 
reportChange(long changeId, int state, boolean isLoggable)83     private void reportChange(long changeId, int state, boolean isLoggable) {
84         int uid = Process.myUid();
85         mChangeReporter.reportChange(uid, changeId, state, isLoggable);
86     }
87 
88 }
89