• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.providers.media;
18 
19 import android.content.ContentProvider;
20 import android.content.ContentResolver;
21 import android.content.Context;
22 import android.content.ContextWrapper;
23 import android.content.pm.ProviderInfo;
24 import android.os.Bundle;
25 import android.os.UserHandle;
26 import android.provider.CloudMediaProvider;
27 import android.provider.MediaStore;
28 import android.provider.Settings;
29 import android.test.mock.MockContentProvider;
30 import android.test.mock.MockContentResolver;
31 
32 import androidx.annotation.NonNull;
33 import androidx.annotation.VisibleForTesting;
34 
35 import com.android.providers.media.cloudproviders.CloudProviderPrimary;
36 import com.android.providers.media.cloudproviders.FlakyCloudProvider;
37 import com.android.providers.media.dao.FileRow;
38 import com.android.providers.media.flags.Flags;
39 import com.android.providers.media.photopicker.PhotoPickerProvider;
40 import com.android.providers.media.photopicker.PickerSyncController;
41 import com.android.providers.media.util.FileUtils;
42 
43 import java.io.File;
44 import java.util.Optional;
45 
46 /**
47  * Class to support mocking Context class for tests.
48  */
49 public class IsolatedContext extends ContextWrapper {
50     private final File mDir;
51     private final MockContentResolver mResolver;
52     private final MediaProvider mMediaProvider;
53     private final UserHandle mUserHandle;
54     private final FlakyCloudProvider mFlakyCloudProvider;
55 
IsolatedContext(Context base, String tag, boolean asFuseThread)56     public IsolatedContext(Context base, String tag, boolean asFuseThread) {
57         this(base, tag, asFuseThread, base.getUser());
58     }
59 
IsolatedContext(Context base, String tag, boolean asFuseThread, UserHandle userHandle)60     public IsolatedContext(Context base, String tag, boolean asFuseThread,
61             UserHandle userHandle) {
62         this(base, tag, asFuseThread, userHandle, new TestConfigStore());
63     }
64 
IsolatedContext(Context base, String tag, boolean asFuseThread, UserHandle userHandle, ConfigStore configStore)65     public IsolatedContext(Context base, String tag, boolean asFuseThread,
66             UserHandle userHandle, ConfigStore configStore) {
67         this(base, tag, asFuseThread, userHandle, configStore, new MaliciousAppDetector(base));
68     }
69 
IsolatedContext(Context base, String tag, boolean asFuseThread, MaliciousAppDetector maliciousAppDetector)70     public IsolatedContext(Context base, String tag, boolean asFuseThread,
71             MaliciousAppDetector maliciousAppDetector) {
72         this(base, tag, asFuseThread, base.getUser(), new TestConfigStore(), maliciousAppDetector);
73     }
74 
IsolatedContext(Context base, String tag, boolean asFuseThread, UserHandle userHandle, ConfigStore configStore, MaliciousAppDetector maliciousAppDetector)75     public IsolatedContext(Context base, String tag, boolean asFuseThread,
76             UserHandle userHandle, ConfigStore configStore,
77             MaliciousAppDetector maliciousAppDetector) {
78         super(base);
79         mDir = new File(base.getFilesDir(), tag);
80         mDir.mkdirs();
81         FileUtils.deleteContents(mDir);
82 
83         mResolver = new MockContentResolver(this);
84         mUserHandle = userHandle;
85 
86         mMediaProvider = getMockedMediaProvider(asFuseThread, configStore, maliciousAppDetector);
87         attachInfoAndAddProvider(base, mMediaProvider, MediaStore.AUTHORITY);
88 
89         MediaDocumentsProvider documentsProvider = new MediaDocumentsProvider();
90         attachInfoAndAddProvider(base, documentsProvider, MediaDocumentsProvider.AUTHORITY);
91 
92         mResolver.addProvider(Settings.AUTHORITY, new MockContentProvider() {
93             @Override
94             public Bundle call(String method, String request, Bundle args) {
95                 return Bundle.EMPTY;
96             }
97         });
98 
99         PhotoPickerProvider photoPickerProvider = new PhotoPickerProvider();
100         attachInfoAndAddProvider(base, photoPickerProvider,
101                 PickerSyncController.LOCAL_PICKER_PROVIDER_AUTHORITY);
102 
103         final CloudMediaProvider cmp = new CloudProviderPrimary();
104         attachInfoAndAddProvider(base, cmp, CloudProviderPrimary.AUTHORITY);
105 
106         mFlakyCloudProvider = new FlakyCloudProvider();
107         attachInfoAndAddProvider(base, mFlakyCloudProvider, FlakyCloudProvider.AUTHORITY);
108 
109         MediaStore.waitForIdle(mResolver);
110     }
111 
getMockedMediaProvider(boolean asFuseThread, ConfigStore configStore, MaliciousAppDetector maliciousAppDetector)112     private MediaProvider getMockedMediaProvider(boolean asFuseThread,
113             ConfigStore configStore, MaliciousAppDetector maliciousAppDetector) {
114         return new MediaProvider() {
115             @Override
116             public boolean isFuseThread() {
117                 return asFuseThread;
118             }
119 
120             @Override
121             protected ConfigStore provideConfigStore() {
122                 return configStore;
123             }
124 
125             @Override
126             protected DatabaseBackupAndRecovery createDatabaseBackupAndRecovery() {
127                 return new TestDatabaseBackupAndRecovery(configStore, getVolumeCache());
128             }
129 
130             @Override
131             protected void storageNativeBootPropertyChangeListener() {
132                 // Ignore this as test app cannot read device config
133             }
134 
135             @Override
136             protected void updateQuotaTypeForUri(@NonNull FileRow row) {
137                 return;
138             }
139 
140             @Override
141             boolean shouldLockdownMediaStoreVersion() {
142                 // TODO(b/370999570): Set to true once Baklava is in dev
143                 return false;
144             }
145 
146             @Override
147             protected MaliciousAppDetector createMaliciousAppDetector() {
148                 return maliciousAppDetector;
149             }
150 
151             @Override
152             protected boolean shouldCheckForMaliciousActivity() {
153                 return Flags.enableMaliciousAppDetector();
154             }
155 
156             @Override
157             protected void enforcePermissionCheckForOemMetadataUpdate(){
158 
159             }
160         };
161     }
162 
163     @Override
164     public File getDatabasePath(String name) {
165         return new File(mDir, name);
166     }
167 
168     @Override
169     public ContentResolver getContentResolver() {
170         return mResolver;
171     }
172 
173     @Override
174     public UserHandle getUser() {
175         return mUserHandle;
176     }
177 
178     public void setPickerUriResolver(PickerUriResolver resolver) {
179         mMediaProvider.setUriResolver(resolver);
180     }
181 
182     public void attachInfoAndAddProvider(Context base, ContentProvider provider,
183             String authority) {
184         final ProviderInfo info = base.getPackageManager().resolveContentProvider(authority, 0);
185         if (info != null) {
186             provider.attachInfo(this, info);
187             mResolver.addProvider(authority, provider);
188         }
189     }
190 
191     /**
192      * @return {@link DatabaseHelper} The external database helper used by the test {@link
193      * IsolatedContext}
194      */
195     public DatabaseHelper getExternalDatabase() throws IllegalStateException {
196         Optional<DatabaseHelper> helper =
197                 mMediaProvider.getDatabaseHelper(DatabaseHelper.EXTERNAL_DATABASE_NAME);
198         if (helper.isPresent()) {
199             return helper.get();
200         } else {
201             throw new IllegalStateException("Failed to get Database helper");
202         }
203     }
204 
205     @VisibleForTesting
206     public void setFlakyCloudProviderToFlakeInTheNextRequest() {
207         mFlakyCloudProvider.setToFlakeInTheNextRequest();
208     }
209 
210     @VisibleForTesting
211     public void resetFlakyCloudProviderToNotFlakeInTheNextRequest() {
212         mFlakyCloudProvider.resetToNotFlakeInTheNextRequest();
213     }
214 }
215