1 /* 2 * Copyright (C) 2007 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 com.android.server.content; 18 19 import static org.mockito.ArgumentMatchers.any; 20 import static org.mockito.ArgumentMatchers.anyBoolean; 21 import static org.mockito.ArgumentMatchers.anyInt; 22 import static org.mockito.ArgumentMatchers.argThat; 23 import static org.mockito.ArgumentMatchers.eq; 24 import static org.mockito.Mockito.mock; 25 import static org.mockito.Mockito.times; 26 import static org.mockito.Mockito.verify; 27 import static org.mockito.Mockito.when; 28 29 import android.app.ActivityManager; 30 import android.app.ActivityManagerInternal; 31 import android.content.ContentResolver; 32 import android.database.ContentObserver; 33 import android.database.IContentObserver; 34 import android.net.Uri; 35 import android.os.Binder; 36 import android.os.Handler; 37 import android.os.Looper; 38 import android.os.UserHandle; 39 import android.util.ArraySet; 40 41 import androidx.test.runner.AndroidJUnit4; 42 43 import com.android.server.LocalServices; 44 import com.android.server.content.ContentService.ObserverCollector; 45 import com.android.server.content.ContentService.ObserverNode; 46 47 import org.junit.Test; 48 import org.junit.runner.RunWith; 49 import org.mockito.ArgumentMatcher; 50 51 import java.util.Arrays; 52 53 /** 54 * atest FrameworksServicesTests:com.android.server.content.ObserverNodeTest 55 */ 56 @RunWith(AndroidJUnit4.class) 57 public class ObserverNodeTest { 58 static class TestObserver extends ContentObserver { TestObserver()59 public TestObserver() { 60 super(new Handler(Looper.getMainLooper())); 61 } 62 } 63 64 @Test testUri()65 public void testUri() { 66 final int myUserHandle = UserHandle.myUserId(); 67 68 ObserverNode root = new ObserverNode(""); 69 Uri[] uris = new Uri[] { 70 Uri.parse("content://c/a/"), 71 Uri.parse("content://c/"), 72 Uri.parse("content://x/"), 73 Uri.parse("content://c/b/"), 74 Uri.parse("content://c/a/a1/1/"), 75 Uri.parse("content://c/a/a1/2/"), 76 Uri.parse("content://c/b/1/"), 77 Uri.parse("content://c/b/2/"), 78 }; 79 80 int[] nums = new int[] {4, 7, 1, 4, 2, 2, 3, 3}; 81 82 // special case 83 root.addObserverLocked(uris[0], new TestObserver().getContentObserver(), false, root, 84 0, 0, myUserHandle); 85 for(int i = 1; i < uris.length; i++) { 86 root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), true, root, 87 0, 0, myUserHandle); 88 } 89 90 for (int i = nums.length - 1; i >=0; --i) { 91 final ObserverCollector collector = mock(ObserverCollector.class); 92 root.collectObserversLocked(uris[i], 0, null, false, 0, myUserHandle, collector); 93 verify(collector, times(nums[i])).collect( 94 any(), anyInt(), anyBoolean(), any(), anyInt(), anyInt()); 95 } 96 } 97 98 @Test testUriNotNotify()99 public void testUriNotNotify() { 100 final int myUserHandle = UserHandle.myUserId(); 101 102 ObserverNode root = new ObserverNode(""); 103 Uri[] uris = new Uri[] { 104 Uri.parse("content://c/"), 105 Uri.parse("content://x/"), 106 Uri.parse("content://c/a/"), 107 Uri.parse("content://c/b/"), 108 Uri.parse("content://c/a/1/"), 109 Uri.parse("content://c/a/2/"), 110 Uri.parse("content://c/b/1/"), 111 Uri.parse("content://c/b/2/"), 112 }; 113 int[] nums = new int[] {7, 1, 3, 3, 1, 1, 1, 1}; 114 115 for(int i = 0; i < uris.length; i++) { 116 root.addObserverLocked(uris[i], new TestObserver().getContentObserver(), false, root, 117 0, 0, myUserHandle); 118 } 119 120 for (int i = uris.length - 1; i >=0; --i) { 121 final ObserverCollector collector = mock(ObserverCollector.class); 122 root.collectObserversLocked(uris[i], 0, null, false, 0, myUserHandle, collector); 123 verify(collector, times(nums[i])).collect( 124 any(), anyInt(), anyBoolean(), any(), anyInt(), anyInt()); 125 } 126 } 127 128 @Test testCluster()129 public void testCluster() throws Exception { 130 final int myUserHandle = UserHandle.myUserId(); 131 132 // Assume everything is foreground during our test 133 final ActivityManagerInternal ami = mock(ActivityManagerInternal.class); 134 when(ami.getUidProcessState(anyInt())) 135 .thenReturn(ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); 136 LocalServices.removeServiceForTest(ActivityManagerInternal.class); 137 LocalServices.addService(ActivityManagerInternal.class, ami); 138 139 final IContentObserver observer = mock(IContentObserver.class); 140 when(observer.asBinder()).thenReturn(new Binder()); 141 142 final ObserverNode root = new ObserverNode(""); 143 root.addObserverLocked(Uri.parse("content://authority/"), observer, 144 true, root, 0, 1000, myUserHandle); 145 146 final ObserverCollector collector = new ObserverCollector(); 147 root.collectObserversLocked(Uri.parse("content://authority/1"), 0, null, false, 148 0, myUserHandle, collector); 149 root.collectObserversLocked(Uri.parse("content://authority/1"), 0, null, false, 150 ContentResolver.NOTIFY_INSERT, myUserHandle, collector); 151 root.collectObserversLocked(Uri.parse("content://authority/2"), 0, null, false, 152 ContentResolver.NOTIFY_INSERT, myUserHandle, collector); 153 root.collectObserversLocked(Uri.parse("content://authority/2"), 0, null, false, 154 ContentResolver.NOTIFY_UPDATE, myUserHandle, collector); 155 collector.dispatch(); 156 157 // We should only cluster when all other arguments are equal 158 verify(observer).onChangeEtc(eq(false), argThat(new UriSetMatcher( 159 Uri.parse("content://authority/1"))), 160 eq(0), anyInt()); 161 verify(observer).onChangeEtc(eq(false), argThat(new UriSetMatcher( 162 Uri.parse("content://authority/1"), 163 Uri.parse("content://authority/2"))), 164 eq(ContentResolver.NOTIFY_INSERT), anyInt()); 165 verify(observer).onChangeEtc(eq(false), argThat(new UriSetMatcher( 166 Uri.parse("content://authority/2"))), 167 eq(ContentResolver.NOTIFY_UPDATE), anyInt()); 168 } 169 170 private static class UriSetMatcher implements ArgumentMatcher<Uri[]> { 171 private final ArraySet<Uri> uris; 172 UriSetMatcher(Uri... uris)173 public UriSetMatcher(Uri... uris) { 174 this.uris = new ArraySet<>(Arrays.asList(uris)); 175 } 176 177 @Override matches(Uri[] uris)178 public boolean matches(Uri[] uris) { 179 final ArraySet<Uri> test = new ArraySet<>(Arrays.asList(uris)); 180 return this.uris.equals(test); 181 } 182 } 183 } 184