1 /*
2  * Copyright (C) 2017 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.content.pm;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.IntDef;
21 import android.annotation.IntRange;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.TestApi;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 import android.util.Pair;
28 
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.List;
35 import java.util.Objects;
36 
37 /**
38  * This class provides information for a shared library. There are
39  * four types of shared libraries: builtin - non-updatable part of
40  * the OS; dynamic - updatable backwards-compatible dynamically linked;
41  * static - non backwards-compatible emulating static linking;
42  * SDK - updatable backwards-incompatible dynamically loaded.
43  */
44 public final class SharedLibraryInfo implements Parcelable {
45 
46     /** @hide */
47     @IntDef(flag = true, prefix = { "TYPE_" }, value = {
48             TYPE_BUILTIN,
49             TYPE_DYNAMIC,
50             TYPE_STATIC,
51             TYPE_SDK_PACKAGE,
52     })
53     @Retention(RetentionPolicy.SOURCE)
54     public @interface Type{}
55 
56     /**
57      * Shared library type: this library is a part of the OS
58      * and cannot be updated or uninstalled.
59      */
60     public static final int TYPE_BUILTIN = 0;
61 
62     /**
63      * Shared library type: this library is backwards-compatible, can
64      * be updated, and updates can be uninstalled. Clients link against
65      * the latest version of the library.
66      */
67     public static final int TYPE_DYNAMIC = 1;
68 
69     /**
70      * Shared library type: this library is <strong>not</strong> backwards
71      * -compatible, can be updated and updates can be uninstalled. Clients
72      * link against a specific version of the library.
73      *
74      * Static shared libraries simulate static linking while allowing for
75      * multiple clients to reuse the same instance of the library.
76      */
77     public static final int TYPE_STATIC = 2;
78 
79     /**
80      * SDK package shared library type: this library is <strong>not</strong>
81      * compatible between versions, can be updated and updates can be
82      * uninstalled. Clients depend on a specific version of the library.
83      *
84      * SDK packages are not loaded automatically by the OS and rely
85      * e.g. on 3P libraries to make them available for the clients.
86      */
87     public static final int TYPE_SDK_PACKAGE = 3;
88 
89     /**
90      * Constant for referring to an undefined version.
91      */
92     public static final int VERSION_UNDEFINED = -1;
93 
94     private final String mPath;
95     private final String mPackageName;
96     private final String mName;
97     private final List<String> mCodePaths;
98 
99     private final long mVersion;
100     private final @Type int mType;
101     private final boolean mIsNative;
102     private final VersionedPackage mDeclaringPackage;
103     private final List<VersionedPackage> mDependentPackages;
104 
105     private final List<VersionedPackage> mOptionalDependentPackages;
106     private List<SharedLibraryInfo> mDependencies;
107 
108     /**
109      * Creates a new instance.
110      *
111      * @param codePaths         For a non {@link #TYPE_BUILTIN builtin} library, the locations of
112      *                          jars of
113      *                          this shared library. Null for builtin library.
114      * @param name              The lib name.
115      * @param version           The lib version if not builtin.
116      * @param type              The lib type.
117      * @param declaringPackage  The package that declares the library.
118      * @param dependentPackages The packages that depend on the library.
119      * @param isNative          indicate if this shared lib is a native lib or not (i.e. java)
120      * @hide
121      */
SharedLibraryInfo(String path, String packageName, List<String> codePaths, String name, long version, int type, VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages, List<SharedLibraryInfo> dependencies, boolean isNative)122     public SharedLibraryInfo(String path, String packageName, List<String> codePaths,
123             String name, long version, int type,
124             VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages,
125             List<SharedLibraryInfo> dependencies, boolean isNative) {
126         mPath = path;
127         mPackageName = packageName;
128         mCodePaths = codePaths;
129         mName = name;
130         mVersion = version;
131         mType = type;
132         mDeclaringPackage = declaringPackage;
133         mDependentPackages = dependentPackages;
134         mDependencies = dependencies;
135         mIsNative = isNative;
136         mOptionalDependentPackages = null;
137     }
138 
139     /**
140      * Creates a new instance.
141      *
142      * @param codePaths For a non {@link #TYPE_BUILTIN builtin} library, the locations of jars of
143      *                  this shared library. Null for builtin library.
144      * @param name The lib name.
145      * @param version The lib version if not builtin.
146      * @param type The lib type.
147      * @param declaringPackage The package that declares the library.
148      * @param isNative indicate if this shared lib is a native lib or not (i.e. java)
149      * @param allDependentPackages All packages that depend on the library (including the optional
150      *                             sdk libraries).
151      *
152      * @hide
153      */
SharedLibraryInfo(String path, String packageName, List<String> codePaths, String name, long version, int type, VersionedPackage declaringPackage, List<SharedLibraryInfo> dependencies, boolean isNative, Pair<List<VersionedPackage>, List<Boolean>> allDependentPackages)154     public SharedLibraryInfo(String path, String packageName, List<String> codePaths,
155             String name, long version, int type,
156             VersionedPackage declaringPackage,
157             List<SharedLibraryInfo> dependencies, boolean isNative,
158             Pair<List<VersionedPackage>, List<Boolean>> allDependentPackages) {
159         mPath = path;
160         mPackageName = packageName;
161         mCodePaths = codePaths;
162         mName = name;
163         mVersion = version;
164         mType = type;
165         mDeclaringPackage = declaringPackage;
166         mDependencies = dependencies;
167         mIsNative = isNative;
168 
169         var allDependents = allDependentPackages.first;
170         var usesLibOptional = allDependentPackages.second;
171         mDependentPackages = allDependents;
172         List<VersionedPackage> optionalDependents = null;
173         if (mType == SharedLibraryInfo.TYPE_SDK_PACKAGE
174                 && Flags.sdkLibIndependence() && allDependents != null
175                 && usesLibOptional != null
176                 && allDependents.size() == usesLibOptional.size()) {
177             for (int k = 0; k < allDependents.size(); k++) {
178                 VersionedPackage versionedPackage = allDependents.get(k);
179                 if (usesLibOptional.get(k)) {
180                     if (optionalDependents == null) {
181                         optionalDependents = new ArrayList<>();
182                     }
183                     optionalDependents.add(versionedPackage);
184                 }
185             }
186         }
187         mOptionalDependentPackages = optionalDependents;
188     }
189 
SharedLibraryInfo(Parcel parcel)190     private SharedLibraryInfo(Parcel parcel) {
191         mPath = parcel.readString8();
192         mPackageName = parcel.readString8();
193         if (parcel.readInt() != 0) {
194             mCodePaths = Arrays.asList(parcel.createString8Array());
195         } else {
196             mCodePaths = null;
197         }
198         mName = parcel.readString8();
199         mVersion = parcel.readLong();
200         mType = parcel.readInt();
201         mDeclaringPackage =
202                 parcel.readParcelable(null, android.content.pm.VersionedPackage.class);
203         mDependentPackages =
204                 parcel.readArrayList(null, android.content.pm.VersionedPackage.class);
205         mDependencies = parcel.createTypedArrayList(SharedLibraryInfo.CREATOR);
206         mIsNative = parcel.readBoolean();
207         mOptionalDependentPackages = parcel.readParcelableList(new ArrayList<>(),
208                 VersionedPackage.class.getClassLoader(), VersionedPackage.class);
209     }
210 
211     /**
212      * Gets the type of this library.
213      *
214      * @return The library type.
215      */
getType()216     public @Type int getType() {
217         return mType;
218     }
219 
220     /**
221      * Tells whether this library is a native shared library or not.
222      *
223      * @hide
224      */
225     @TestApi
isNative()226     public boolean isNative() {
227         return mIsNative;
228     }
229 
230     /**
231      * Gets the library name an app defines in its manifest
232      * to depend on the library.
233      *
234      * @return The name.
235      */
getName()236     public String getName() {
237         return mName;
238     }
239 
240     /**
241      * If the shared library is a jar file, returns the path of that jar. Null otherwise.
242      * Only libraries with TYPE_BUILTIN are in jar files.
243      *
244      * @return The path.
245      *
246      * @hide
247      */
getPath()248     public @Nullable String getPath() {
249         return mPath;
250     }
251 
252     /**
253      * If the shared library is an apk, returns the package name. Null otherwise.
254      * Only libraries with TYPE_DYNAMIC or TYPE_STATIC are in apks.
255      *
256      * @return The package name.
257      *
258      * @hide
259      */
getPackageName()260     public @Nullable String getPackageName() {
261         return mPackageName;
262     }
263 
264     /**
265      * Get all code paths for that library.
266      *
267      * @return All code paths.
268      *
269      * @hide
270      */
271     @TestApi
getAllCodePaths()272     public @NonNull List<String> getAllCodePaths() {
273         if (getPath() != null) {
274             // Builtin library.
275             ArrayList<String> list = new ArrayList<>();
276             list.add(getPath());
277             return list;
278         } else {
279             // Static or dynamic library.
280             return Objects.requireNonNull(mCodePaths);
281         }
282     }
283 
284     /**
285      * Add a library dependency to that library. Note that this
286      * should be called under the package manager lock.
287      *
288      * @hide
289      */
addDependency(@ullable SharedLibraryInfo info)290     public void addDependency(@Nullable SharedLibraryInfo info) {
291         if (info == null) {
292             // For convenience of the caller, allow null to be passed.
293             // This can happen when we create the dependencies of builtin
294             // libraries.
295             return;
296         }
297         if (mDependencies == null) {
298             mDependencies = new ArrayList<>();
299         }
300         mDependencies.add(info);
301     }
302 
303     /**
304      * Clear all dependencies.
305      *
306      * @hide
307      */
clearDependencies()308     public void clearDependencies() {
309         mDependencies = null;
310     }
311 
312     /**
313      * Gets the libraries this library directly depends on. Note that
314      * the package manager prevents recursive dependencies when installing
315      * a package.
316      *
317      * @return The dependencies.
318      *
319      * @hide
320      */
getDependencies()321     public @Nullable List<SharedLibraryInfo> getDependencies() {
322         return mDependencies;
323     }
324 
325     /**
326      * @deprecated Use {@link #getLongVersion()} instead.
327      */
328     @Deprecated
getVersion()329     public @IntRange(from = -1) int getVersion() {
330         return mVersion < 0 ? (int) mVersion : (int) (mVersion & 0x7fffffff);
331     }
332 
333     /**
334      * Gets the version of the library. For {@link #TYPE_STATIC static} libraries
335      * this is the declared version and for {@link #TYPE_DYNAMIC dynamic} and
336      * {@link #TYPE_BUILTIN builtin} it is {@link #VERSION_UNDEFINED} as these
337      * are not versioned.
338      *
339      * @return The version.
340      */
getLongVersion()341     public @IntRange(from = -1) long getLongVersion() {
342         return mVersion;
343     }
344 
345     /**
346      * @removed
347      */
isBuiltin()348     public boolean isBuiltin() {
349         return mType == TYPE_BUILTIN;
350     }
351 
352     /**
353      * @removed
354      */
isDynamic()355     public boolean isDynamic() {
356         return mType == TYPE_DYNAMIC;
357     }
358 
359     /**
360      * @removed
361      */
isStatic()362     public boolean isStatic() {
363         return mType == TYPE_STATIC;
364     }
365 
366     /**
367      * @hide
368      */
isSdk()369     public boolean isSdk() {
370         return mType == TYPE_SDK_PACKAGE;
371     }
372 
373     /**
374      * Gets the package that declares the library.
375      *
376      * @return The package declaring the library.
377      */
getDeclaringPackage()378     public @NonNull VersionedPackage getDeclaringPackage() {
379         return mDeclaringPackage;
380     }
381 
382     /**
383      * Gets the packages that depend on the library.
384      *
385      * NOTE: the list also contains the result of {@link #getOptionalDependentPackages}.
386      *
387      * @return The dependent packages.
388      */
getDependentPackages()389     public @NonNull List<VersionedPackage> getDependentPackages() {
390         if (mDependentPackages == null) {
391             return Collections.emptyList();
392         }
393         return mDependentPackages;
394     }
395 
396     /**
397      * Gets the packages that optionally depend on the library.
398      *
399      * @return The dependent packages.
400      */
401     @FlaggedApi(Flags.FLAG_SDK_LIB_INDEPENDENCE)
getOptionalDependentPackages()402     public @NonNull List<VersionedPackage> getOptionalDependentPackages() {
403         if (mOptionalDependentPackages == null) {
404             return Collections.emptyList();
405         }
406         return mOptionalDependentPackages;
407     }
408 
409     @Override
describeContents()410     public int describeContents() {
411         return 0;
412     }
413 
414     @Override
toString()415     public String toString() {
416         return "SharedLibraryInfo{name:" + mName + ", type:" + typeToString(mType)
417                 + ", version:" + mVersion + (!getDependentPackages().isEmpty()
418                 ? " has dependents" : "") + "}";
419     }
420 
421     @Override
writeToParcel(Parcel parcel, int flags)422     public void writeToParcel(Parcel parcel, int flags) {
423         parcel.writeString8(mPath);
424         parcel.writeString8(mPackageName);
425         if (mCodePaths != null) {
426             parcel.writeInt(1);
427             parcel.writeString8Array(mCodePaths.toArray(new String[mCodePaths.size()]));
428         } else {
429             parcel.writeInt(0);
430         }
431         parcel.writeString8(mName);
432         parcel.writeLong(mVersion);
433         parcel.writeInt(mType);
434         parcel.writeParcelable(mDeclaringPackage, flags);
435         parcel.writeList(mDependentPackages);
436         parcel.writeTypedList(mDependencies);
437         parcel.writeBoolean(mIsNative);
438         parcel.writeParcelableList(mOptionalDependentPackages, flags);
439     }
440 
typeToString(int type)441     private static String typeToString(int type) {
442         switch (type) {
443             case TYPE_BUILTIN: {
444                 return "builtin";
445             }
446             case TYPE_DYNAMIC: {
447                 return "dynamic";
448             }
449             case TYPE_STATIC: {
450                 return "static";
451             }
452             case TYPE_SDK_PACKAGE: {
453                 return "sdk";
454             }
455             default: {
456                 return "unknown";
457             }
458         }
459     }
460 
461     public static final @android.annotation.NonNull Parcelable.Creator<SharedLibraryInfo> CREATOR =
462             new Parcelable.Creator<SharedLibraryInfo>() {
463         public SharedLibraryInfo createFromParcel(Parcel source) {
464             return new SharedLibraryInfo(source);
465         }
466 
467         public SharedLibraryInfo[] newArray(int size) {
468             return new SharedLibraryInfo[size];
469         }
470     };
471 }
472