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 android.app.admin; 18 19 import android.content.ComponentName; 20 import android.os.Bundle; 21 import android.os.Parcelable; 22 import android.os.PersistableBundle; 23 24 import com.android.internal.util.Preconditions; 25 import com.android.modules.utils.ModifiedUtf8; 26 27 import java.io.UTFDataFormatException; 28 import java.util.ArrayDeque; 29 import java.util.Queue; 30 31 /** 32 * Utility class containing methods to verify the max allowed size of certain policy types. 33 * 34 * @hide 35 */ 36 public class PolicySizeVerifier { 37 38 // FrameworkParsingPackageUtils#MAX_FILE_NAME_SIZE, Android packages are used in dir names. 39 public static final int MAX_PACKAGE_NAME_LENGTH = 223; 40 41 public static final int MAX_PROFILE_NAME_LENGTH = 200; 42 public static final int MAX_LONG_SUPPORT_MESSAGE_LENGTH = 20000; 43 public static final int MAX_SHORT_SUPPORT_MESSAGE_LENGTH = 200; 44 public static final int MAX_ORG_NAME_LENGTH = 200; 45 46 /** 47 * Throw if string argument is too long to be serialized. 48 */ enforceMaxStringLength(String str, String argName)49 public static void enforceMaxStringLength(String str, String argName) { 50 try { 51 long len = ModifiedUtf8.countBytes(str, /* throw error if too long */ true); 52 } catch (UTFDataFormatException e) { 53 throw new IllegalArgumentException(argName + " too long"); 54 } 55 } 56 57 /** 58 * Throw if package name exceeds max size allowed by the system. 59 */ enforceMaxPackageNameLength(String pkg)60 public static void enforceMaxPackageNameLength(String pkg) { 61 Preconditions.checkArgument( 62 pkg.length() <= MAX_PACKAGE_NAME_LENGTH, "Package name too long"); 63 } 64 65 /** 66 * Throw if persistable bundle contains any string that's too long to be serialized. 67 */ enforceMaxStringLength(PersistableBundle bundle, String argName)68 public static void enforceMaxStringLength(PersistableBundle bundle, String argName) { 69 // Persistable bundles can have other persistable bundles as values, traverse with a queue. 70 Queue<PersistableBundle> queue = new ArrayDeque<>(); 71 queue.add(bundle); 72 while (!queue.isEmpty()) { 73 PersistableBundle current = queue.remove(); 74 for (String key : current.keySet()) { 75 enforceMaxStringLength(key, "key in " + argName); 76 Object value = current.get(key); 77 if (value instanceof String str) { 78 enforceMaxStringLength(str, "string value in " + argName); 79 } else if (value instanceof String[] strArray) { 80 for (String str : strArray) { 81 enforceMaxStringLength(str, "string value in " + argName); 82 } 83 } else if (value instanceof PersistableBundle persistableBundle) { 84 queue.add(persistableBundle); 85 } 86 } 87 } 88 } 89 90 /** 91 * Throw if bundle contains any string that's too long to be serialized. This follows the 92 * serialization logic in BundlePolicySerializer#writeBundle. 93 */ enforceMaxBundleFieldsLength(Bundle bundle)94 public static void enforceMaxBundleFieldsLength(Bundle bundle) { 95 Queue<Bundle> queue = new ArrayDeque<>(); 96 queue.add(bundle); 97 while (!queue.isEmpty()) { 98 Bundle current = queue.remove(); 99 for (String key : current.keySet()) { 100 enforceMaxStringLength(key, "key in Bundle"); 101 Object value = current.get(key); 102 if (value instanceof String str) { 103 enforceMaxStringLength(str, "string value in Bundle with " 104 + "key" + key); 105 } else if (value instanceof String[] strArray) { 106 for (String str : strArray) { 107 enforceMaxStringLength(str, "string value in Bundle with" 108 + " key" + key); 109 } 110 } else if (value instanceof Bundle b) { 111 queue.add(b); 112 } 113 else if (value instanceof Parcelable[] parcelableArray) { 114 for (Parcelable parcelable : parcelableArray) { 115 if (!(parcelable instanceof Bundle)) { 116 throw new IllegalArgumentException("bundle-array can only hold " 117 + "Bundles"); 118 } 119 queue.add((Bundle) parcelable); 120 } 121 } 122 } 123 } 124 } 125 126 /** 127 * Throw if ComponentName contains any string that's too long to be serialized. 128 */ enforceMaxComponentNameLength(ComponentName componentName)129 public static void enforceMaxComponentNameLength(ComponentName componentName) { 130 enforceMaxPackageNameLength(componentName.getPackageName()); 131 enforceMaxStringLength(componentName.flattenToString(), "componentName"); 132 } 133 134 /** 135 * Truncates char sequence to maximum length, nulls are ignored. 136 */ truncateIfLonger(CharSequence input, int maxLength)137 public static CharSequence truncateIfLonger(CharSequence input, int maxLength) { 138 return input == null || input.length() <= maxLength 139 ? input 140 : input.subSequence(0, maxLength); 141 } 142 } 143