1 /*
2  * Copyright (C) 2024 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.odp.module.common;
18 
19 import static android.content.pm.PackageManager.GET_META_DATA;
20 import static android.content.pm.PackageManager.GET_SIGNING_CERTIFICATES;
21 import static android.content.pm.PackageManager.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES;
22 import static android.federatedcompute.common.ClientConstants.ODP_AOSP_BUILT_APEX_NAME;
23 import static android.federatedcompute.common.ClientConstants.ODP_APEX_KEYWORD;
24 import static android.federatedcompute.common.ClientConstants.ODP_MAINLINE_SIGNED_APEX_NAME;
25 
26 import android.annotation.NonNull;
27 import android.annotation.Nullable;
28 import android.content.Context;
29 import android.content.pm.ApplicationInfo;
30 import android.content.pm.PackageInfo;
31 import android.content.pm.PackageManager;
32 import android.content.pm.Signature;
33 import android.content.pm.SigningInfo;
34 
35 import libcore.util.HexEncoding;
36 
37 import java.security.MessageDigest;
38 import java.security.NoSuchAlgorithmException;
39 import java.util.List;
40 
41 /**
42  * PackageUtils for OnDevicePersonalization module.
43  *
44  * @hide
45  */
46 public class PackageUtils {
PackageUtils()47     private PackageUtils() {
48     }
49 
50     /**
51      * Computes the SHA256 digest of some data.
52      *
53      * @param data The data.
54      * @return The digest or null if an error occurs.
55      */
56     @Nullable
computeSha256DigestBytes(@onNull byte[] data)57     public static byte[] computeSha256DigestBytes(@NonNull byte[] data) {
58         MessageDigest messageDigest;
59         try {
60             messageDigest = MessageDigest.getInstance("SHA256");
61         } catch (NoSuchAlgorithmException e) {
62             /* can't happen */
63             return null;
64         }
65 
66         messageDigest.update(data);
67 
68         return messageDigest.digest();
69     }
70 
71     /**
72      * Retrieves the certDigest of the given packageName
73      *
74      * @param context Context of the calling service
75      * @param packageName Package name owning the certDigest
76      * @return certDigest of the given packageName
77      */
78     @Nullable
getCertDigest(@onNull Context context, @NonNull String packageName)79     public static String getCertDigest(@NonNull Context context, @NonNull String packageName)
80             throws PackageManager.NameNotFoundException {
81         PackageInfo sdkPackageInfo =
82                 context.getPackageManager()
83                         .getPackageInfo(
84                                 packageName,
85                                 PackageManager.PackageInfoFlags.of(
86                                         GET_SIGNING_CERTIFICATES
87                                                 | MATCH_STATIC_SHARED_AND_SDK_LIBRARIES));
88         SigningInfo signingInfo = sdkPackageInfo.signingInfo;
89         Signature[] signatures =
90                 signingInfo != null ? signingInfo.getSigningCertificateHistory() : null;
91         byte[] digest = PackageUtils.computeSha256DigestBytes(signatures[0].toByteArray());
92         return new String(HexEncoding.encode(digest));
93     }
94 
95     /**
96      * Determines if a package is debuggable
97      *
98      * @return true if the package is debuggable, false otherwise
99      */
isPackageDebuggable(@onNull Context context, @NonNull String packageName)100     public static boolean isPackageDebuggable(@NonNull Context context, @NonNull String packageName)
101             throws PackageManager.NameNotFoundException {
102         ApplicationInfo sdkApplicationInfo =
103                 context.getPackageManager()
104                         .getApplicationInfo(
105                                 packageName, PackageManager.ApplicationInfoFlags.of(GET_META_DATA));
106         return (sdkApplicationInfo.flags &= ApplicationInfo.FLAG_DEBUGGABLE) != 0;
107     }
108 
109     /**
110      * Get the apex version of OnDevicePersonalization.
111      *
112      * @param context The context of the calling process.
113      * @return The long version code of OnDevicePersonalization apex. If there is no name match,
114      *     then return -1L.
115      */
getApexVersion(Context context)116     public static long getApexVersion(Context context) {
117         try {
118             PackageInfo odpMainlineApexInfo = context.getPackageManager()
119                     .getPackageInfo(ODP_MAINLINE_SIGNED_APEX_NAME, PackageManager.MATCH_APEX);
120             if (odpMainlineApexInfo != null && odpMainlineApexInfo.isApex) {
121                 return odpMainlineApexInfo.getLongVersionCode();
122             }
123 
124             PackageInfo odpAospApexInfo = context.getPackageManager()
125                     .getPackageInfo(ODP_AOSP_BUILT_APEX_NAME, PackageManager.MATCH_APEX);
126             if (odpAospApexInfo != null && odpAospApexInfo.isApex) {
127                 return odpAospApexInfo.getLongVersionCode();
128             }
129         } catch (PackageManager.NameNotFoundException e) {
130         }
131 
132         List<PackageInfo> installedPackages =
133                 context.getPackageManager().getInstalledPackages(
134                         PackageManager.PackageInfoFlags.of(PackageManager.MATCH_APEX));
135         for (PackageInfo pkg : installedPackages) {
136             if (pkg.packageName.contains(ODP_APEX_KEYWORD) && pkg.isApex) {
137                 return pkg.getLongVersionCode();
138             }
139         }
140         return -1L;
141     }
142 }
143