• 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.cts.rollback.lib;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.IntentFilter;
23 import android.content.pm.PackageInfo;
24 import android.content.pm.PackageInstaller;
25 import android.content.pm.PackageManager;
26 import android.content.pm.VersionedPackage;
27 import android.content.rollback.PackageRollbackInfo;
28 import android.content.rollback.RollbackInfo;
29 import android.content.rollback.RollbackManager;
30 
31 import androidx.test.InstrumentationRegistry;
32 
33 import java.io.IOException;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.concurrent.BlockingQueue;
37 import java.util.concurrent.LinkedBlockingQueue;
38 
39 /**
40  * Utilities to facilitate testing rollbacks.
41  */
42 public class Utils {
43     /**
44      * Returns the version of the given package installed on device.
45      * Returns -1 if the package is not currently installed.
46      */
getInstalledVersion(String packageName)47     public static long getInstalledVersion(String packageName) {
48         Context context = InstrumentationRegistry.getContext();
49         PackageManager pm = context.getPackageManager();
50         try {
51             PackageInfo info = pm.getPackageInfo(packageName, PackageManager.MATCH_APEX);
52             return info.getLongVersionCode();
53         } catch (PackageManager.NameNotFoundException e) {
54             return -1;
55         }
56     }
57 
58     /**
59      * Gets the RollbackManager for the instrumentation context.
60      */
getRollbackManager()61     public static RollbackManager getRollbackManager() {
62         Context context = InstrumentationRegistry.getContext();
63         RollbackManager rm = (RollbackManager) context.getSystemService(Context.ROLLBACK_SERVICE);
64         if (rm == null) {
65             throw new AssertionError("Failed to get RollbackManager");
66         }
67         return rm;
68     }
69 
70     /**
71      * Returns a rollback for the given package name in the list of
72      * rollbacks. Returns null if there are no available rollbacks, and throws
73      * an assertion if there is more than one.
74      */
getRollback(List<RollbackInfo> rollbacks, String packageName)75     private static RollbackInfo getRollback(List<RollbackInfo> rollbacks, String packageName) {
76         RollbackInfo found = null;
77         for (RollbackInfo rollback : rollbacks) {
78             for (PackageRollbackInfo info : rollback.getPackages()) {
79                 if (packageName.equals(info.getPackageName())) {
80                     if (found != null) {
81                         throw new AssertionError("Multiple available matching rollbacks found");
82                     }
83                     found = rollback;
84                     break;
85                 }
86             }
87         }
88         return found;
89     }
90 
91     /**
92      * Returns a rollback for the given rollback Id, if found. Otherwise, returns null.
93      */
getRollbackById(List<RollbackInfo> rollbacks, int rollbackId)94     private static RollbackInfo getRollbackById(List<RollbackInfo> rollbacks, int rollbackId) {
95         for (RollbackInfo rollback :rollbacks) {
96             if (rollback.getRollbackId() == rollbackId) {
97                 return rollback;
98             }
99         }
100         return null;
101     }
102 
103     /**
104      * Returns an available rollback for the given package name. Returns null
105      * if there are no available rollbacks, and throws an assertion if there
106      * is more than one.
107      */
getAvailableRollback(String packageName)108     public static RollbackInfo getAvailableRollback(String packageName) {
109         RollbackManager rm = getRollbackManager();
110         return getRollback(rm.getAvailableRollbacks(), packageName);
111     }
112 
113     /**
114      * Returns a recently committed rollback for the given package name. Returns null
115      * if there are no available rollbacks, and throws an assertion if there
116      * is more than one.
117      */
getCommittedRollback(String packageName)118     public static RollbackInfo getCommittedRollback(String packageName) {
119         RollbackManager rm = getRollbackManager();
120         return getRollback(rm.getRecentlyCommittedRollbacks(), packageName);
121     }
122 
123     /**
124      * Returns a recently committed rollback for the given rollback Id.
125      * Returns null if no committed rollback with a matching Id was found.
126      */
getCommittedRollbackById(int rollbackId)127     public static RollbackInfo getCommittedRollbackById(int rollbackId) {
128         RollbackManager rm = getRollbackManager();
129         return getRollbackById(rm.getRecentlyCommittedRollbacks(), rollbackId);
130     }
131 
132     /**
133      * Uninstalls the given package.
134      * Does nothing if the package is not installed.
135      * @throws AssertionError if package can't be uninstalled.
136      */
uninstall(String packageName)137     public static void uninstall(String packageName) throws InterruptedException, IOException {
138         // No need to uninstall if the package isn't installed.
139         if (getInstalledVersion(packageName) == -1) {
140             return;
141         }
142 
143         Context context = InstrumentationRegistry.getContext();
144         PackageManager packageManager = context.getPackageManager();
145         PackageInstaller packageInstaller = packageManager.getPackageInstaller();
146         packageInstaller.uninstall(packageName, LocalIntentSender.getIntentSender());
147         Intent result = LocalIntentSender.getIntentSenderResult();
148         int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
149                 PackageInstaller.STATUS_FAILURE);
150         if (status == -1) {
151             throw new AssertionError("PENDING USER ACTION");
152         } else if (status > 0) {
153             String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
154             throw new AssertionError(message == null ? "UNKNOWN FAILURE" : message);
155         }
156     }
157 
158     /**
159      * Commit the given rollback.
160      * @throws AssertionError if the rollback fails.
161      */
rollback(int rollbackId, TestApp... causePackages)162     public static void rollback(int rollbackId, TestApp... causePackages)
163             throws InterruptedException {
164         List<VersionedPackage> causes = new ArrayList<>();
165         for (TestApp cause : causePackages) {
166             causes.add(cause.getVersionedPackage());
167         }
168 
169         RollbackManager rm = getRollbackManager();
170         rm.commitRollback(rollbackId, causes, LocalIntentSender.getIntentSender());
171         Intent result = LocalIntentSender.getIntentSenderResult();
172         int status = result.getIntExtra(RollbackManager.EXTRA_STATUS,
173                 RollbackManager.STATUS_FAILURE);
174         if (status != RollbackManager.STATUS_SUCCESS) {
175             String message = result.getStringExtra(RollbackManager.EXTRA_STATUS_MESSAGE);
176             throw new AssertionError(message);
177         }
178     }
179 
180     /**
181      * Waits for the given session to be marked as ready.
182      * Throws an assertion if the session fails.
183      */
waitForSessionReady(int sessionId)184     public static void waitForSessionReady(int sessionId) {
185         BlockingQueue<PackageInstaller.SessionInfo> sessionStatus = new LinkedBlockingQueue<>();
186         BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
187             @Override
188             public void onReceive(Context context, Intent intent) {
189                 PackageInstaller.SessionInfo info =
190                         intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
191                 if (info != null && info.getSessionId() == sessionId) {
192                     if (info.isStagedSessionReady() || info.isStagedSessionFailed()) {
193                         try {
194                             sessionStatus.put(info);
195                         } catch (InterruptedException e) {
196                             throw new AssertionError(e);
197                         }
198                     }
199                 }
200             }
201         };
202         IntentFilter sessionUpdatedFilter =
203                 new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
204 
205         Context context = InstrumentationRegistry.getContext();
206         context.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter);
207 
208         PackageInstaller installer = context.getPackageManager().getPackageInstaller();
209         PackageInstaller.SessionInfo info = installer.getSessionInfo(sessionId);
210 
211         try {
212             if (info.isStagedSessionReady() || info.isStagedSessionFailed()) {
213                 sessionStatus.put(info);
214             }
215 
216             info = sessionStatus.take();
217             context.unregisterReceiver(sessionUpdatedReceiver);
218             if (info.isStagedSessionFailed()) {
219                 throw new AssertionError(info.getStagedSessionErrorMessage());
220             }
221         } catch (InterruptedException e) {
222             throw new AssertionError(e);
223         }
224     }
225 }
226 
227