• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.server.healthconnect.migration;
18 
19 import android.Manifest;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.pm.PackageInfo;
23 import android.content.pm.PackageManager;
24 import android.content.pm.ResolveInfo;
25 import android.health.connect.Constants;
26 import android.health.connect.HealthConnectManager;
27 import android.util.Slog;
28 
29 import libcore.util.HexEncoding;
30 
31 import java.security.MessageDigest;
32 import java.security.NoSuchAlgorithmException;
33 import java.util.ArrayList;
34 import java.util.List;
35 import java.util.stream.Collectors;
36 
37 /** @hide */
38 public class MigrationUtils {
39     private static final String TAG = "HealthConnectMigrationUtils";
40 
41     /**
42      * Filters and returns the package names of applications which hold permission {@link
43      * android.Manifest.permission#MIGRATE_HEALTH_CONNECT_DATA}.
44      *
45      * @return List of filtered app package names which hold the specified permission
46      */
filterPermissions(Context context)47     public static List<String> filterPermissions(Context context) {
48         if (android.health.connect.Constants.DEBUG) {
49             Slog.d(TAG, "Calling filterPermissions()");
50         }
51 
52         String[] permissions = new String[] {Manifest.permission.MIGRATE_HEALTH_CONNECT_DATA};
53 
54         List<PackageInfo> packageInfos =
55                 context.getPackageManager()
56                         .getPackagesHoldingPermissions(
57                                 permissions, PackageManager.PackageInfoFlags.of(0));
58 
59         List<String> permissionFilteredPackages =
60                 packageInfos.stream().map(info -> info.packageName).collect(Collectors.toList());
61 
62         if (android.health.connect.Constants.DEBUG) {
63             Slog.d(TAG, "permissionFilteredPackages : " + permissionFilteredPackages);
64         }
65         return permissionFilteredPackages;
66     }
67 
68     /**
69      * Filters and returns the package names of applications which handle intent {@link
70      * android.health.connect.HealthConnectManager#ACTION_SHOW_MIGRATION_INFO}.
71      *
72      * @param permissionFilteredPackages List of app package names holding permission {@link
73      *     android.Manifest.permission#MIGRATE_HEALTH_CONNECT_DATA}
74      * @return List of filtered app package names which handle the specified intent action
75      */
filterIntent( Context context, List<String> permissionFilteredPackages)76     public static List<String> filterIntent(
77             Context context, List<String> permissionFilteredPackages) {
78         return filterIntent(context, permissionFilteredPackages, PackageManager.MATCH_ALL);
79     }
80 
81     /**
82      * Filters and returns the package names of applications which handle intent {@link
83      * android.health.connect.HealthConnectManager#ACTION_SHOW_MIGRATION_INFO}.
84      *
85      * @param permissionFilteredPackages List of app package names holding permission {@link
86      *     android.Manifest.permission#MIGRATE_HEALTH_CONNECT_DATA}
87      * @param flags Additional option flags to modify the data returned.
88      * @return List of filtered app package names which handle the specified intent action
89      */
filterIntent( Context context, List<String> permissionFilteredPackages, int flags)90     public static List<String> filterIntent(
91             Context context, List<String> permissionFilteredPackages, int flags) {
92         if (android.health.connect.Constants.DEBUG) {
93             Slog.d(TAG, "Calling filterIntents()");
94         }
95 
96         List<String> filteredPackages = new ArrayList<String>(permissionFilteredPackages.size());
97 
98         for (String packageName : permissionFilteredPackages) {
99 
100             if (android.health.connect.Constants.DEBUG) {
101                 Slog.d(TAG, "Checking intent for package : " + packageName);
102             }
103 
104             Intent intentToCheck =
105                     new Intent(HealthConnectManager.ACTION_SHOW_MIGRATION_INFO)
106                             .setPackage(packageName);
107 
108             ResolveInfo resolveResult =
109                     context.getPackageManager()
110                             .resolveActivity(
111                                     intentToCheck, PackageManager.ResolveInfoFlags.of(flags));
112 
113             if (resolveResult != null) {
114                 filteredPackages.add(packageName);
115             }
116         }
117         if (Constants.DEBUG) {
118             Slog.d(TAG, "filteredPackages : " + filteredPackages);
119         }
120         return filteredPackages;
121     }
122 
123     /** Computes the SHA256 digest of the input data. */
124     @SuppressWarnings("NullAway") // TODO(b/317029272): fix this suppression
computeSha256DigestBytes(byte[] data)125     public static String computeSha256DigestBytes(byte[] data) {
126         MessageDigest messageDigest;
127         try {
128             messageDigest = MessageDigest.getInstance("SHA256");
129         } catch (NoSuchAlgorithmException e) {
130             return null;
131         }
132         messageDigest.update(data);
133 
134         return HexEncoding.encodeToString(messageDigest.digest(), /* uppercase= */ true);
135     }
136 
137     /** Checks if the package is stub by checking if its installer source is not set. */
isPackageStub(Context context, String packageName)138     public static boolean isPackageStub(Context context, String packageName) {
139         try {
140             return context.getPackageManager()
141                             .getInstallSourceInfo(packageName)
142                             .getInstallingPackageName()
143                     == null;
144         } catch (PackageManager.NameNotFoundException e) {
145             Slog.w(TAG, "Package not found " + packageName);
146         }
147         return false;
148     }
149 }
150