1 /*
2  * Copyright 2015 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 package android.media.misc.cts;
17 
18 import static org.junit.Assume.assumeTrue;
19 
20 import android.app.Activity;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.os.Bundle;
24 import android.util.Log;
25 
26 import junit.framework.Assert;
27 
28 public class ResourceManagerStubActivity extends Activity {
29     // Define all the error codes specific to this test case here
30     // Test case was skipped as there aren't any supported decoder(s).
31     public static final int RESULT_CODE_NO_DECODER = Activity.RESULT_FIRST_USER + 1;
32     // Test case was skipped as there aren't any supported encoder(s).
33     public static final int RESULT_CODE_NO_ENCODER = Activity.RESULT_FIRST_USER + 2;
34     // Test case was skipped as the device doesn't have any camera available for recording.
35     public static final int RESULT_CODE_NO_CAMERA = Activity.RESULT_FIRST_USER + 3;
36 
37     private static final String TAG = "ResourceManagerStubActivity";
38     private final Object mFinishEvent = new Object();
39     private int[] mRequestCodes = {0, 1};
40     private int[] mResults = {RESULT_CANCELED, RESULT_CANCELED};
41     private int mNumResults = 0;
42     private int mType1 = ResourceManagerTestActivityBase.TYPE_NONSECURE;
43     private int mType2 = ResourceManagerTestActivityBase.TYPE_NONSECURE;
44     private boolean mWaitForReclaim = true;
45     private boolean mStartedOnlyOneActivity = false;
46 
47     private static final String ERROR_INSUFFICIENT_RESOURCES =
48             "* Please check if the omx component is returning OMX_ErrorInsufficientResources " +
49             "properly when the codec failure is due to insufficient resource.\n";
50     private static final String ERROR_SUPPORTS_MULTIPLE_SECURE_CODECS =
51             "* Please check if this platform supports multiple concurrent secure codec " +
52             "instances. If not, please add below setting in /etc/media_codecs.xml in order " +
53             "to pass the test:\n" +
54             "    <Settings>\n" +
55             "       <Setting name=\"supports-multiple-secure-codecs\" value=\"false\" />\n" +
56             "    </Settings>\n";
57     private static final String ERROR_SUPPORTS_SECURE_WITH_NON_SECURE_CODEC =
58             "* Please check if this platform supports co-exist of secure and non-secure codec. " +
59             "If not, please add below setting in /etc/media_codecs.xml in order to pass the " +
60             "test:\n" +
61             "    <Settings>\n" +
62             "       <Setting name=\"supports-secure-with-non-secure-codec\" value=\"false\" />\n" +
63             "    </Settings>\n";
64 
65     @Override
onCreate(Bundle savedInstanceState)66     protected void onCreate(Bundle savedInstanceState) {
67         super.onCreate(savedInstanceState);
68     }
69 
70     @Override
onActivityResult(int requestCode, int resultCode, Intent data)71     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
72         Log.d(TAG, "Activity " + requestCode + " finished with resultCode " + resultCode);
73         mResults[requestCode] = resultCode;
74         if (++mNumResults == mResults.length || mStartedOnlyOneActivity) {
75             synchronized (mFinishEvent) {
76                 mFinishEvent.notify();
77             }
78         }
79     }
80 
processActivityResults()81     private void processActivityResults() {
82         boolean result = true;
83         for (int i = 0; result && i < mResults.length; ++i) {
84             switch (mResults[i]) {
85                 case RESULT_OK:
86                     // Activity completed successfully.
87                     break;
88                 case RESULT_CODE_NO_DECODER:
89                     assumeTrue("Test case was skipped as there aren't any supported decoder(s).",
90                             false);
91                     break;
92                 case RESULT_CODE_NO_ENCODER:
93                     assumeTrue("Test case was skipped as there aren't any supported encoder(s).",
94                             false);
95                     break;
96                 case RESULT_CODE_NO_CAMERA:
97                     assumeTrue("Test case was skipped as the device doesn't have any "
98                             + "camera available for recording.", false);
99                     break;
100                 default:
101                     Log.e(TAG, "Result from activity " + i + " is a fail.");
102                     result = false;
103                     break;
104             }
105         }
106 
107         if (!result) {
108             String failMessage = "The potential reasons for the failure:\n";
109             StringBuilder reasons = new StringBuilder();
110             reasons.append(ERROR_INSUFFICIENT_RESOURCES);
111             if (mType1 != mType2) {
112                 reasons.append(ERROR_SUPPORTS_SECURE_WITH_NON_SECURE_CODEC);
113             }
114             if (mType1 == ResourceManagerTestActivityBase.TYPE_MIX
115                     && mType2 == ResourceManagerTestActivityBase.TYPE_SECURE) {
116                 reasons.append(ERROR_SUPPORTS_MULTIPLE_SECURE_CODECS);
117             }
118             Assert.assertTrue(failMessage + reasons.toString(), result);
119         }
120     }
121 
waitForActivitiesToComplete()122     private void waitForActivitiesToComplete() throws InterruptedException {
123         // Wait for all the activities to complete.
124         synchronized (mFinishEvent) {
125             while (mNumResults < mResults.length) {
126                 mFinishEvent.wait();
127             }
128         }
129     }
130 
waitForOneActivityToComplete()131     private void waitForOneActivityToComplete() throws InterruptedException {
132         // Wait for one activity to complete.
133         synchronized (mFinishEvent) {
134             while (mNumResults != 1) {
135                 mFinishEvent.wait();
136             }
137         }
138     }
139 
testReclaimResource(int type1, int type2, boolean highResolutionForActivity1, boolean highResolutionForActivity2)140     public void testReclaimResource(int type1, int type2, boolean highResolutionForActivity1,
141             boolean highResolutionForActivity2) throws InterruptedException {
142         mType1 = type1;
143         mType2 = type2;
144         if (type1 != ResourceManagerTestActivityBase.TYPE_MIX && type1 != type2) {
145             // in this case, activity2 may not need to reclaim codec from activity1.
146             mWaitForReclaim = false;
147         } else {
148             mWaitForReclaim = true;
149         }
150         Thread thread = new Thread() {
151             @Override
152             public void run() {
153                 try {
154                     Context context = getApplicationContext();
155                     Intent intent1 = new Intent(context, ResourceManagerTestActivity1.class);
156                     intent1.putExtra("test-type", mType1);
157                     intent1.putExtra("wait-for-reclaim", mWaitForReclaim);
158                     intent1.putExtra("high-resolution", highResolutionForActivity1);
159                     startActivityForResult(intent1, mRequestCodes[0]);
160                     Thread.sleep(5000);  // wait for process to launch and allocate all codecs.
161 
162                     Intent intent2 = new Intent(context, ResourceManagerTestActivity2.class);
163                     intent2.putExtra("test-type", mType2);
164                     intent2.putExtra("high-resolution", highResolutionForActivity2);
165                     startActivityForResult(intent2, mRequestCodes[1]);
166 
167                     waitForActivitiesToComplete();
168                 } catch (Exception e) {
169                     Log.d(TAG, "testReclaimResource got exception " + e.toString());
170                 }
171             }
172         };
173         thread.start();
174         Log.i(TAG, "Started and waiting for Activities");
175         thread.join();
176         Log.i(TAG, "Activities completed");
177 
178         processActivityResults();
179     }
180 
testVideoCodecReclaim(boolean highResolution, String mimeType)181     public void testVideoCodecReclaim(boolean highResolution, String mimeType)
182             throws InterruptedException {
183         Thread thread = new Thread() {
184             @Override
185             public void run() {
186                 try {
187                     Context context = getApplicationContext();
188 
189                     // Start the transcoding activity first.
190                     Log.d(TAG, "Starting ResourceManagerCodecActivity");
191                     Intent decoders = new Intent(context, ResourceManagerCodecActivity.class);
192                     decoders.putExtra("high-resolution", highResolution);
193                     decoders.putExtra("mime", mimeType);
194                     startActivityForResult(decoders, mRequestCodes[0]);
195                     // wait for ResourceManagerCodecActivity to launch and allocate all codecs.
196                     Thread.sleep(5000);
197 
198                     Log.d(TAG, "Starting ResourceManagerRecorderActivity");
199                     // Start the Camera Recording next.
200                     Intent recorder = new Intent(context, ResourceManagerRecorderActivity.class);
201                     recorder.putExtra("high-resolution", highResolution);
202                     recorder.putExtra("mime", mimeType);
203                     startActivityForResult(recorder, mRequestCodes[1]);
204 
205                     waitForActivitiesToComplete();
206                 } catch (Exception e) {
207                     Log.d(TAG, "testVideoCodecReclaim got exception " + e.toString());
208                 }
209             }
210         };
211 
212         thread.start();
213         Log.i(TAG, "Started and waiting for Activities");
214         thread.join();
215         Log.i(TAG, "Activities completed");
216 
217         processActivityResults();
218     }
219 
doTestReclaimResource(String codecName, String mimeType, int width, int height)220     public void doTestReclaimResource(String codecName, String mimeType, int width, int height)
221             throws InterruptedException {
222         mWaitForReclaim = true;
223         Thread thread = new Thread() {
224             @Override
225             public void run() {
226                 try {
227                     Context context = getApplicationContext();
228                     Intent intent1 = new Intent(context, ResourceManagerTestActivity1.class);
229                     intent1.putExtra("test-type", mType1);
230                     intent1.putExtra("wait-for-reclaim", mWaitForReclaim);
231                     intent1.putExtra("name", codecName);
232                     intent1.putExtra("mime", mimeType);
233                     intent1.putExtra("width", width);
234                     intent1.putExtra("height", height);
235                     startActivityForResult(intent1, mRequestCodes[0]);
236                     Thread.sleep(5000);  // wait for process to launch and allocate all codecs.
237 
238                     Intent intent2 = new Intent(context, ResourceManagerTestActivity2.class);
239                     intent2.putExtra("test-type", mType2);
240                     intent2.putExtra("name", codecName);
241                     intent2.putExtra("mime", mimeType);
242                     intent2.putExtra("width", width);
243                     intent2.putExtra("height", height);
244                     startActivityForResult(intent2, mRequestCodes[1]);
245 
246                     waitForActivitiesToComplete();
247                 } catch (Exception e) {
248                     Log.d(TAG, "doTestReclaimResource got exception " + e.toString());
249                 }
250             }
251         };
252 
253         thread.start();
254         Log.i(TAG, "Started and waiting for Activities");
255         thread.join();
256         Log.i(TAG, "Activities completed");
257 
258         processActivityResults();
259     }
260 
261     /**
262      * creates allowable number of decoders at given resolution.
263      * All the codecs are configured with the default importance (highest)
264      * But, when we get a INSUFFICIENT_RESOURCE, we lower the importance of the
265      * first codec so that we can create/start one more codec by reclaiming the
266      * first codec (that has lower importance now)
267      */
doTestCodecImportanceReclaimResource( String codecName, String mimeType, int width, int height, boolean highResolution, boolean changeImportanceAtConfig)268     public void doTestCodecImportanceReclaimResource(
269             String codecName, String mimeType, int width, int height,
270             boolean highResolution, boolean changeImportanceAtConfig)
271             throws InterruptedException {
272         mWaitForReclaim = true;
273         Thread thread = new Thread() {
274             @Override
275             public void run() {
276                 try {
277                     Context context = getApplicationContext();
278                     Intent intent = new Intent(context, ResourceManagerTestActivity2.class);
279                     intent.putExtra("test-type", mType1);
280                     intent.putExtra("wait-for-reclaim", mWaitForReclaim);
281                     intent.putExtra("name", codecName);
282                     intent.putExtra("mime", mimeType);
283                     if (width == 0 || height == 0) {
284                         intent.putExtra("high-resolution", highResolution);
285                     } else {
286                         intent.putExtra("width", width);
287                         intent.putExtra("height", height);
288                     }
289                     if (changeImportanceAtConfig) {
290                         intent.putExtra("codec-importance-at-config", true);
291                     } else {
292                         intent.putExtra("codec-importance-later", true);
293                     }
294                     mStartedOnlyOneActivity = true;
295                     startActivityForResult(intent, mRequestCodes[0]);
296                     waitForOneActivityToComplete();
297                 } catch (Exception e) {
298                     Log.d(TAG, "doTestCodecImportanceReclaimResource got exception "
299                             + e.toString());
300                 }
301             }
302         };
303 
304         thread.start();
305         Log.i(TAG, "Started and waiting for Activities");
306         thread.join();
307         Log.i(TAG, "Activities completed");
308 
309         // Since we have started one activity, set the other activity code to success.
310         mResults[1] = RESULT_OK;
311         processActivityResults();
312     }
313 }
314