Could not resolve requested type for CAST : Integer

Caused by: org.hibernate.QueryException: Could not resolve requested type for CAST : Integer

解决方案

##把大写 I 修改为 小写 i
##例:Hql 语句中 cast(a.id as Integer) 修改为 cast(a.id as integer)

请查看以下的C++代码的编写要求,请根据代码要求开始编写代码 PURPOSE: This file is a proforma for the EEET2246 Laboratory Code Submission/Test 1. This file defines the assessment task which is worth 10% of course in total - there is no other documentation. At the BASIC FUNCTIONAL REQUIREMENTS level, your goal is to write a program that takes two numbers from the command line and perform and arithmetic operations with them. Additionally your program must be able to take three command line arguments where if the last argument is 'a' an addition is performed, and if 's' then subtraction is performed with the first two arguments. At the FUNCTIONAL REQUIREMENTS level you will be required to extend on the functionality so that the third argument can also be 'm' for multiplication,'d' for division and 'p' for exponential operations, using the first two arguments as the operands. Additionally, at this level basic error detection and handling will be required. The functionality of this lab is relatively simple: + - / * and "raised to the power of" The emphasis in this lab is to achieve the BASIC FUNCTIONALITY REQUIREMENTS first. Once you a basic program functioning then you should attempt the FUNCTIONALITY REQUIREMENTS and develop your code so that it can handle a full range of error detection and handling. ___________________________________________________________________________________________ ___ GENERAL SPECIFICATIONS (mostly common to all three EEET2246 Laboratory Code Submissions): G1. You must rename your file to lab1_1234567.cpp, where 1234567 is your student number. Your filename MUST NEVER EVER contain any spaces. _under_score_is_Fine. You do not need to include the 's' in front of your student number. Canvas will rename your submission by adding a -1, -2 etc. if you resubmit your solution file - This is acceptable. G2. Edit the name/email address string in the main() function to your student number, student email and student name. The format of the student ID line is CSV (Comma Separated Variables) with NO SPACES- student_id,student_email,student_name When the program is run without any operands i.e. simply the name of the executable such as: lab1_1234567.exe the program MUST print student ID string in Comma Separated Values (CSV) format with no spaces. For example the following text should be outputted to the console updated with your student details: "1234567,s1234567@student.rmit.edu.au,FirstName_LastName" G3. All outputs are a single error character or a numerical number, as specified by the FUNCTIONAL REQURMENTS, followed by a linefeed ( endl or \n). G4. DO NOT add more than what is specified to the expected console output. Do NOT add additional information, text or comments to the output console that are not defined within the SPECIFICATIONS/FUNCTIONAL REQURMENTS. G5. DO NOT use 'cin', system("pause"), getchar(), gets(), etc. type functions. Do NOT ask for user input from the keyboard. All input MUST be specified on the command line separated by blank spaces (i.e. use the argv and argc input parameters). G6. DO NOT use the characters: * / \ : ^ ? in your command line arguments as your user input. These are special character and may not be processed as expected, potentially resulting in undefined behaviour of your program. G7. All input MUST be specified on the command line separated by blank spaces (i.e. use the argc and argv[] input parameters). All input and output is case sensitive unless specified. G8. You should use the Integrated Debugging Environment (IDE) to change input arguments during the development process. G9. When your code exits the 'main()' function using the 'return' command, you MUST use zero as the return value. This requirement is for exiting the 'main()' function ONLY. A return value other than zero will indicate that something went wrong to the Autotester and no marks will be awarded. G10. User-defined functions and/or class declarations must be written before the 'main()' function. This is a requirement of the Autotester and failure to do so will result in your code scoring 0% as it will not be compiled correctly by the Autotester. Do NOT put any functions/class definitions after the 'main()' function or modify the comments and blank lines at the end of this file. G11. You MUST run this file as part of a Project - No other *.cpp or *.h files should be added to your solution. G12. You are not permitted to add any other #includes statements to your solution. The only libraries permitted to be used are the ones predefined in this file. G13. Under no circumstances is your code solution to contain any go_to labels - Please note that the '_' has been added to this description so that this file does not flag the Autotester. Code that contains go_to label like syntax will score 0% and will be treated as code that does not compile. G14. Under no circumstances is your code solution to contain any exit_(0) type functions. Please note that the '_' has been added to this description so that this file does not flag the Autotester. Your solution must always exit with a return 0; in main(). Code that contains exit_(0); label like syntax will score 0% and will be treated as code that does not compile. G15. Under no circumstances is your code solution to contain an infinite loop constructs within it. For example usage of while(1), for(int i; ; i++) or anything similar is not permitted. Code that contains an infinite loop will result in a score of 0% for your assessment submission and will be treated as code that does not compile. G16. Under no circumstances is your code solution to contain any S_l_e_e_p() or D_e_l_a_y() like statements - Please note that the '_' has been added to this description so that this file does not flag the Autotester. You can use such statements during your development, however you must remove delays or sleeps from your code prior to submission. This is important, as the Autotester will only give your solution a limited number of seconds to complete (i.e. return 0 in main()). Failure for your code to complete the required operation/s within the allotted execution window will result in the Autotester scoring your code 0 marks for that test. To test if your code will execute in the allotted execution window, check that it completes within a similar time frame as the provided sample binary. G17. Under no circumstances is your code solution to contain any characters from the extended ASCII character set or International typeset characters. Although such characters may compile under a normal system, they will result in your code potentially not compiling under the Autotester environment. Therefore, please ensure that you only use characters: a ... z, A ... Z, 0 ... 9 as your variable and function names or within any literal strings defined within your code. Literal strings can contain '.', '_', '-', and other basic symbols. G18. All output to console should be directed to the standard console (stdout) via cout. Do not use cerr or clog to print to the console. G19. The file you submit must compile without issues as a self contained *.cpp file. Code that does not compile will be graded as a non-negotiable zero mark. G20. All binary numbers within this document have the prefix 0b. This notation is not C++ compliant (depending on the C++ version), however is used to avoid confusion between decimal, hexadecimal and binary number formats within the description and specification provided in this document. For example the number 10 in decimal could be written as 0xA in hexadecimal or 0b1010 in binary. It can equally be written with leading zeroes such as: 0x0A or 0b00001010. For output to the console screen you should only ever display the numerical characters only and omit the 0x or 0b prefixes (unless it is specifically requested). ___________________________________________________________________________________________ ___ BASIC FUNCTIONAL REQUIREMENTS (doing these alone will only get you to approximately 40%): M1. For situation where NO command line arguments are passed to your program: M1.1 Your program must display your correct student details in the format: "3939723,s3939723@student.rmit.edu.au,Yang_Yang" M2. For situation where TWO command line arguments are passed to your program: M2.1 Your program must perform an addition operation, taking the first two arguments as the operands and display only the result to the console with a new line character. Example1: lab1_1234567.exe 10 2 which should calculate 10 + 2 = 12, i.e. the last (and only) line on the console will be: 12 M3. For situations where THREE command line arguments are passed to your program: M3.1 If the third argument is 'a', your program must perform an addition operation, taking the first two arguments as the operands and display only the result to the console with a new line character. M3.2 If the third argument is 's', your program must perform a subtraction operation, taking the first two arguments as the operands and display only the result to the console with a new line character. The second input argument should be subtracted from the first input argument. M4. For situations where less than TWO or more than THREE command line arguments are passed to your program, your program must display the character 'P' to the console with a new line character. M5. For specifications M1 to M4 inclusive: M5.1 Program must return 0 under all situations at exit. M5.2 Program must be able to handle integer arguments. M5.3 Program must be able to handle floating point arguments. M5.4 Program must be able to handle one integer and one floating point argument in any order. Example2: lab1_1234567.exe 10 2 s which should calculate 10 - 2 = 8, i.e. the last (and only) line on the console will be: 8 Example3: lab1_1234567.exe 10 2 which should calculate 10 + 2 = 12, i.e. the last (and only) line on the console will be: 12 Example4: lab1_1234567.exe 10 4 a which should calculate 10 + 4 = 14, i.e. the last (and only) line on the console will be: 14 ___________________________________________________________________________________________ ___ FUNCTIONAL REQUIREMENTS (to get over approximately 50%): E1. For situations where THREE command line arguments (other than 'a' or 's') are passed to your program: E1.1 If the third argument is 'm', your program must perform a multiplication operation, taking the first two arguments as the operands and display only the result to the console with a new line character. E1.2 If the third argument is 'd', your program must perform a division operation, taking the first two arguments as the operands and display only the result to the console with a new line character. E1.3 If the third argument is 'p', your program must perform an exponential operation, taking the first argument as the base operand and the second as the exponent operand. The result must be display to the console with a new line character. Hint: Consider using the pow() function, which has the definition: double pow(double base, double exponent); Example5: lab1_1234567.exe 10 2 d which should calculate 10 / 2 = 5, i.e. the last (and only) line on the console will be: 5 Example6: lab1_1234567.exe 10 2 p which should calculate 10 to power of 2 = 100, i.e. the last (and only) line on the console will be: 100 NOTE1: DO NOT use the character ^ in your command line arguments as your user input. Question: Why don't we use characters such as + - * / ^ ? to determine the operation? Answer: Arguments passed via the command line are processed by the operating system before being passed to your program. During this process, special characters such as + - * / ^ ? are stripped from the input argument stream. Therefore, the input characters: + - * / ^ ? will not be tested for by the autotester. See sections G6 and E7. NOTE2: the pow() and powl() function/s only work correctly for given arguments. Hence, your code should output and error if there is a domain error or undefined subset of values. For example, if the result does not produce a real number you code should handle this as an error. This means that if the base is negative you can't accept and exponent between (but not including) -1 and 1. If you get this then, output a MURPHY's LAW error: "Y" and return 0; NOTE3: zero to the power of zero is also undefined, and should also be treated MURPHY's LAW error. So return "Y" and return 0; In Visual Studio, the 0 to the power of 0 will return 1, so you will need to catch this situation manually, else your code will likely calculate the value as 1. ___ REQUIRED ERROR HANDLING (to get over approximately 70%): The following text lists errors you must detect and a priority of testing. NB: order of testing is important as each test is slight more difficult than the previous test. All outputs should either be numerical or upper-case single characters (followed by a new line). Note that case is important: In C, 'V' is not the same as 'v'. (No quotes are required on the output). E2. Valid operator input: If the third input argument is not a valid operation selection, the output shall be 'V'. Valid operators are ONLY (case sensitive): a addition s subtraction m multiplication d division p exponentiation i.e. to the power of: 2 to the power of 3 = 8 (base exponent p) E3. Basic invalid number detection (Required): Valid numbers are all numbers that the "average Engineering graduate" in Australia would consider valid. Therefore if the first two arguments are not valid decimal numbers, the output shall be 'X'. For example: -130 is valid +100 is valid 1.3 is valid 3 is valid 0.3 is valid .3 is valid ABC123 is not valid 1.3.4 is not valid 123abc is not valid ___ ERROR HANDLING (not marked by the autotester): E4. Intermediate invalid number detection (NOT TESTED BY AUTOTESTER - for your consideration only): If the first two arguments are not valid decimal numbers, the output shall be 'X'. Using comma punctuated numbers and scientific formatted numbers are considered valid. For example: 0000.111 is valid 3,000 is valid - NB: atof() will read this as '3' not as 3000 1,000.9 is valid - NB: atof() will read this as '1' not as 1000.9 1.23e2 is valid 2E2 is valid -3e-0.5 is not valid (an integer must follow after the e or E for floating point number to be valid) 2E2.1 is not valid e-1 is not valid .e3 is not valid E5. Advanced invalid number detection (NOT TESTED BY AUTOTESTER - for your consideration only): If the first two arguments are not valid decimal numbers, the output shall be 'X'. 1.3e-1 is valid 1,00.0 is valid - NB: if the comma is not removed atof() will read this as '1' not as 100 +212+21-2 is not valid - NB: mathematical operation on a number of numbers, not ONE number 5/2 is not valid - NB: mathematical operation on a number of numbers, not ONE number HINT: consider the function atof(), which has the definition: double atof (const char* str); Checking the user input for multiple operators (i.e. + or -) is quite a difficult task. One method may involve writing a 'for' loop which steps through the input argv[] counting the number of operators. This process could also be used to count for decimal points and the like. The multiple operator check should be considered an advanced task and developed once the rest of the code is operational. E6. Input number range checking: All input numbers must be between (and including) +2^16 (65536) or -2^16 (-65536). If the operand is out of range i.e. too small or too big, the output shall be 'R'. LARGE NUMBERS: is 1.2e+999 acceptable input ? what happens if you enter such a number ? try and see. Hint: #INF error - where and when does it come up ? SMALL NUMBERS: is 1.2e-999 acceptable input ? what happens if you enter such a number ? try and see. Test it by writing your own test program. E7. ERROR checks which will NOT be performed are: E7.1 Input characters such as: *.* or / or \ or : or any of these characters: * / ^ ? will not be tested for. E7.2 Range check: some computer systems accept numbers of size 9999e999999 while others flag and infinity error. An infinity error becomes an invalid input Therefore: input for valid numbers will only be tested to the maximum 9.9e99 (Note: 9.9e99 is out of range and your program should output 'R') E8. Division by zero should produce output 'M' E9. Error precedence: If multiple errors occur during a program execution event, your program should only display one error code followed by a newline character and then exit (using a return 0; statement). In general, the precedence of the error reported to the console should be displayed in the order that they appear within this proforma. However to clarify the exact order or precedence for the error characters, the precedence of the displayed error code should occur in this order: 'P' - Incorrect number of input command line arguments (see M4) 'X' - Invalid numerical command line argument 'V' - Invalid third input argument 'R' - operand (command line argument) value out of range 'M' - Division by zero 'Y' - MURPHY'S LAW (undefined error) Therefore if an invalid numerical command line argument and an invalid operation argument are passed to the program, the first error code should be displayed to the console, which in this case would be 'X'. Displaying 'V' or 'Y' would be result in a loss of marks. E10. ANYTHING ELSE THAT CAN GO WRONG (MURPHY'S LAW TEST): If there are any other kinds of errors not covered here, the output shall be 'Y'. Rhetorical question: What for example are the error codes that the Power function returns ? If this happens then the output shall be 'Y'. See section E1.3, NOTE2. ___________________________________________________________________________________________ ___ HINTS: - Use debug mode and a breakpoint at the return statement prior to program finish in main. - What string conversion routines, do you know how to convert strings to number? Look carefully as they will be needed to convert a command line parameter to a number and also check for errors. - ERROR CHECKING: The basic programming rules are simple (as covered in lectures): 1) check that the input is valid. 2) check that the output is valid. 3) if any library function returns an error code USE IT !!! CHECK FOR IT !!! - Most conversion routines do have inbuilt error checking - USE IT !!! That means: test for the error condition and take some action if the error is true. If that means more than 50% of your code is error checking, then that's the way it has to be. ____________________________________________________________________________________________ */ // These are the libraries you are allowed to use to write your solution. Do not add any // additional libraries as the auto-tester will be locked down to the following: #include <iostream> #include <cstdlib> #include <time.h> #include <math.h> #include <errno.h> // leave this one in please, it is required by the Autotester! // Do NOT Add or remove any #include statements to this project!! // All library functions required should be covered by the above // include list. Do not add a *.h file for this project as all your // code should be included in this file. using namespace std; const double MAXRANGE = pow(2.0, 16.0); // 65536 const double MINRANGE = -pow(2.0, 16.0); // All functions to be defined below and above main() - NO exceptions !!! Do NOT // define function below main() as your code will fail to compile in the auto-tester. // WRITE ANY USER DEFINED FUNCTIONS HERE (optional) // all function definitions and prototypes to be defined above this line - NO exceptions !!! int main(int argc, char *argv[]) { // ALL CODE (excluding variable declarations) MUST come after the following 'if' statement if (argc == 1) { // When run with just the program name (no parameters) your code MUST print // student ID string in CSV format. i.e. // "studentNumber,student_email,student_name" // eg: "3939723,s3939723@student.rmit.edu.au,Yang_Yang" // No parameters on command line just the program name // Edit string below: eg: "studentNumber,student_email,student_name" cout << "3939723,s3939723@student.rmit.edu.au,Yang_Yang" << endl; // Failure of your program to do this cout statement correctly will result in a // flat 10% marks penalty! Check this outputs correctly when no arguments are // passed to your program before you submit your file! Do it as your last test! // The convention is to return Zero to signal NO ERRORS (please do not change it). return 0; } //--- START YOUR CODE HERE. // The convention is to return Zero to signal NO ERRORS (please do not change it). // If you change it the AutoTester will assume you have made some major error. return 0; } // No code to be placed below this line - all functions to be defined above main() function. // End of file.
08-16
/* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.pinner; import static android.app.ActivityManager.UID_OBSERVER_ACTIVE; import static android.app.ActivityManager.UID_OBSERVER_GONE; import static android.os.Process.SYSTEM_UID; import static com.android.server.flags.Flags.pinGlobalQuota; import static com.android.server.flags.Flags.pinWebview; import android.annotation.EnforcePermission; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.IActivityManager; import android.app.UidObserver; import android.app.pinner.IPinnerService; import android.app.pinner.PinnedFileStat; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.DeviceConfig; import android.provider.DeviceConfigInterface; import android.provider.MediaStore; import android.provider.Settings; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ResolverActivity; import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.wm.ActivityTaskManagerInternal; import dalvik.system.DexFile; import dalvik.system.VMRuntime; import system.ext.loader.core.ExtLoader; import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import sun.misc.Unsafe; // #ifdef OPLUS_EXTENSION_HOOK // Haoran.Xu@ROM.Framework, 2021/07/12, Modify for ALM:1770593 import com.android.server.IPinnerServiceExt; // #endif /* OPLUS_EXTENSION_HOOK */ /** * <p>PinnerService pins important files for key processes in memory.</p> * <p>Files to pin are specified in the config_defaultPinnerServiceFiles * overlay.</p> * <p>Pin the default camera application if specified in config_pinnerCameraApp.</p> * <p>(Optional) Pin experimental carveout regions based on DeviceConfig flags.</p> */ public final class PinnerService extends SystemService { private static final boolean DEBUG = false; private static final String TAG = "PinnerService"; private static final String PIN_META_FILENAME = "pinlist.meta"; private static final int PAGE_SIZE = (int) Os.sysconf(OsConstants._SC_PAGESIZE); private static final int MATCH_FLAGS = PackageManager.MATCH_DEFAULT_ONLY | PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE; private static final int KEY_CAMERA = 0; private static final int KEY_HOME = 1; private static final int KEY_ASSISTANT = 2; // Pin using pinlist.meta when pinning apps. private static boolean PROP_PIN_PINLIST = SystemProperties.getBoolean("pinner.use_pinlist", true); public static final String ANON_REGION_STAT_NAME = "[anon]"; private static final String SYSTEM_GROUP_NAME = "system"; @IntDef({KEY_CAMERA, KEY_HOME, KEY_ASSISTANT}) @Retention(RetentionPolicy.SOURCE) public @interface AppKey {} private final Context mContext; private final Injector mInjector; private final DeviceConfigInterface mDeviceConfigInterface; private final ActivityTaskManagerInternal mAtmInternal; private final ActivityManagerInternal mAmInternal; private final IActivityManager mAm; private final UserManager mUserManager; /** The list of the statically pinned files. */ @GuardedBy("this") private final ArrayMap<String, PinnedFile> mPinnedFiles = new ArrayMap<>(); /** The list of the pinned apps. This is a map from {@link AppKey} to a pinned app. */ @GuardedBy("this") private final ArrayMap<Integer, PinnedApp> mPinnedApps = new ArrayMap<>(); /** * The list of the pinned apps that need to be repinned as soon as the all processes of a given * uid are no longer active. Note that with background dex opt, the new dex/vdex files are only * loaded into the processes once it restarts. So in case background dex opt recompiled these * files, we still need to keep the old ones pinned until the processes restart. * <p> * This is a map from uid to {@link AppKey} */ @GuardedBy("this") private final ArrayMap<Integer, Integer> mPendingRepin = new ArrayMap<>(); /** * A set of {@link AppKey} that are configured to be pinned. */ @GuardedBy("this") private ArraySet<Integer> mPinKeys; // Note that we don't use the `_BOOT` namespace for anonymous pinnings, as we want // them to be responsive to dynamic flag changes for experimentation. private static final String DEVICE_CONFIG_NAMESPACE_ANON_SIZE = DeviceConfig.NAMESPACE_RUNTIME_NATIVE; private static final String DEVICE_CONFIG_KEY_ANON_SIZE = "pin_shared_anon_size"; private static final long DEFAULT_ANON_SIZE = SystemProperties.getLong("pinner.pin_shared_anon_size", 0); private static final long MAX_ANON_SIZE = 2L * (1L << 30); // 2GB private long mPinAnonSize; private long mPinAnonAddress; private long mCurrentlyPinnedAnonSize; // Resource-configured pinner flags; private final boolean mConfiguredToPinCamera; private final int mConfiguredCameraPinBytes; private final int mConfiguredHomePinBytes; private final boolean mConfiguredToPinAssistant; private final int mConfiguredAssistantPinBytes; private final int mConfiguredWebviewPinBytes; // This is the percentage of total device memory that will be used to set the global quota. private final int mConfiguredMaxPinnedMemoryPercentage; // This is the global pinner quota that can be pinned. private long mConfiguredMaxPinnedMemory; // This is the currently pinned memory. private long mCurrentPinnedMemory = 0; private BinderService mBinderService; private PinnerHandler mPinnerHandler = null; // #ifdef OPLUS_EXTENSION_HOOK // Haoran.Xu@ROM.Framework, 2021/07/12, Modify for ALM:1770593 public IPinnerServiceExt mPinnerServiceExt = ExtLoader.type(IPinnerServiceExt.class).create(); // #endif /* OPLUS_EXTENSION_HOOK */ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // If an app has updated, update pinned files accordingly. if (Intent.ACTION_PACKAGE_REPLACED.equals(intent.getAction())) { Uri packageUri = intent.getData(); String packageName = packageUri.getSchemeSpecificPart(); ArraySet<String> updatedPackages = new ArraySet<>(); updatedPackages.add(packageName); update(updatedPackages, true /* force */); } } }; private final DeviceConfig.OnPropertiesChangedListener mDeviceConfigAnonSizeListener = new DeviceConfig.OnPropertiesChangedListener() { @Override public void onPropertiesChanged(DeviceConfig.Properties properties) { if (DEVICE_CONFIG_NAMESPACE_ANON_SIZE.equals(properties.getNamespace()) && properties.getKeyset().contains(DEVICE_CONFIG_KEY_ANON_SIZE)) { refreshPinAnonConfig(); } } }; /** Utility class for testing. */ @VisibleForTesting public static class Injector { protected DeviceConfigInterface getDeviceConfigInterface() { return DeviceConfigInterface.REAL; } protected void publishBinderService(PinnerService service, Binder binderService) { service.publishBinderService("pinner", binderService); } protected PinnedFile pinFileInternal(PinnerService service, String fileToPin, long maxBytesToPin, boolean attemptPinIntrospection) { return service.pinFileInternal(fileToPin, maxBytesToPin, attemptPinIntrospection); } } public PinnerService(Context context) { this(context, new Injector()); } @VisibleForTesting public PinnerService(Context context, Injector injector) { super(context); mContext = context; mInjector = injector; mDeviceConfigInterface = mInjector.getDeviceConfigInterface(); mConfiguredToPinCamera = context.getResources().getBoolean( com.android.internal.R.bool.config_pinnerCameraApp); mConfiguredCameraPinBytes = context.getResources().getInteger( com.android.internal.R.integer.config_pinnerCameraPinBytes); mConfiguredAssistantPinBytes = context.getResources().getInteger( com.android.internal.R.integer.config_pinnerAssistantPinBytes); mConfiguredHomePinBytes = context.getResources().getInteger( com.android.internal.R.integer.config_pinnerHomePinBytes); mConfiguredToPinAssistant = context.getResources().getBoolean( com.android.internal.R.bool.config_pinnerAssistantApp); mConfiguredWebviewPinBytes = context.getResources().getInteger( com.android.internal.R.integer.config_pinnerWebviewPinBytes); mConfiguredMaxPinnedMemoryPercentage = context.getResources().getInteger( com.android.internal.R.integer.config_pinnerMaxPinnedMemoryPercentage); mPinKeys = createPinKeys(); mPinnerHandler = new PinnerHandler(BackgroundThread.get().getLooper()); mAtmInternal = LocalServices.getService(ActivityTaskManagerInternal.class); mAmInternal = LocalServices.getService(ActivityManagerInternal.class); mAm = ActivityManager.getService(); mUserManager = mContext.getSystemService(UserManager.class); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_REPLACED); filter.addDataScheme("package"); mContext.registerReceiver(mBroadcastReceiver, filter); registerUidListener(); registerUserSetupCompleteListener(); mDeviceConfigInterface.addOnPropertiesChangedListener(DEVICE_CONFIG_NAMESPACE_ANON_SIZE, new HandlerExecutor(mPinnerHandler), mDeviceConfigAnonSizeListener); } @Override public void onStart() { if (DEBUG) { Slog.i(TAG, "Starting PinnerService"); } mConfiguredMaxPinnedMemory = (Process.getTotalMemory() * Math.clamp(mConfiguredMaxPinnedMemoryPercentage, 0, 100)) / 100; mBinderService = new BinderService(); mInjector.publishBinderService(this, mBinderService); publishLocalService(PinnerService.class, this); mPinnerHandler.obtainMessage(PinnerHandler.PIN_ONSTART_MSG).sendToTarget(); sendPinAppsMessage(UserHandle.USER_SYSTEM); } /** * Repin apps on user switch. * <p> * If more than one user is using the device each user may set a different preference for the * individual apps. Make sure that user's preference is pinned into memory. */ @Override public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) { int userId = to.getUserIdentifier(); if (!mUserManager.isManagedProfile(userId)) { sendPinAppsMessage(userId); } } @Override public void onUserUnlocking(@NonNull TargetUser user) { final int userId = user.getUserIdentifier(); if (userId != UserHandle.USER_SYSTEM && !mUserManager.isManagedProfile(userId)) { // App pinning for the system should have already been triggered from onStart(). sendPinAppsMessage(userId); } } /** * Update the currently pinned files. * Specifically, this only updates pinning for the apps that need to be pinned. * The other files pinned in onStart will not need to be updated. */ public void update(ArraySet<String> updatedPackages, boolean force) { ArraySet<Integer> pinKeys = getPinKeys(); int currentUser = ActivityManager.getCurrentUser(); for (int i = pinKeys.size() - 1; i >= 0; i--) { int key = pinKeys.valueAt(i); ApplicationInfo info = getInfoForKey(key, currentUser); if (info != null && updatedPackages.contains(info.packageName)) { Slog.i(TAG, "Updating pinned files for " + info.packageName + " force=" + force); sendPinAppMessage(key, currentUser, force); } } // #ifdef OPLUS_EXTENSION_HOOK // Haoran.Xu@ROM.Framework, 2021/07/12, Modify for ALM:1770593 mPinnerServiceExt.updateExt(updatedPackages, force); // #endif /* OPLUS_EXTENSION_HOOK */ } /** Returns information about pinned files and sizes for StatsPullAtomService. */ public List<PinnedFileStats> dumpDataForStatsd() { List<PinnedFileStats> pinnedFileStats = new ArrayList<>(); synchronized (PinnerService.this) { for (PinnedFile pinnedFile : mPinnedFiles.values()) { pinnedFileStats.add(new PinnedFileStats(SYSTEM_UID, pinnedFile)); } for (int key : mPinnedApps.keySet()) { PinnedApp app = mPinnedApps.get(key); for (PinnedFile pinnedFile : mPinnedApps.get(key).mFiles) { pinnedFileStats.add(new PinnedFileStats(app.uid, pinnedFile)); } } } return pinnedFileStats; } /** Wrapper class for statistics for a pinned file. */ public static class PinnedFileStats { public final int uid; public final String filename; public final int sizeKb; protected PinnedFileStats(int uid, PinnedFile file) { this.uid = uid; this.filename = file.fileName.substring(file.fileName.lastIndexOf('/') + 1); this.sizeKb = (int) file.bytesPinned / 1024; } } /** * Handler for on start pinning message */ private void handlePinOnStart() { // Files to pin come from the overlay and can be specified per-device config String[] filesToPin = mContext.getResources().getStringArray( com.android.internal.R.array.config_defaultPinnerServiceFiles); // #ifdef OPLUS_EXTENSION_HOOK // Chucheng.Ye@ANDROID.RESCONTROL, 2021/08/03, add for customize pinner file. filesToPin = mPinnerServiceExt.replaceDefaultFiles(filesToPin); // #endif /* OPLUS_EXTENSION_HOOK */ // Continue trying to pin each file even if we fail to pin some of them for (String fileToPin : filesToPin) { pinFile(fileToPin, Integer.MAX_VALUE, /*appInfo=*/null, /*groupName=*/SYSTEM_GROUP_NAME, true); } refreshPinAnonConfig(); } /** * Registers a listener to repin the home app when user setup is complete, as the home intent * initially resolves to setup wizard, but once setup is complete, it will resolve to the * regular home app. */ private void registerUserSetupCompleteListener() { Uri userSetupCompleteUri = Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE); mContext.getContentResolver().registerContentObserver( userSetupCompleteUri, false, new ContentObserver(null) { @Override public void onChange(boolean selfChange, Uri uri) { if (userSetupCompleteUri.equals(uri)) { if (mConfiguredHomePinBytes > 0) { sendPinAppMessage(KEY_HOME, ActivityManager.getCurrentUser(), true /* force */); } } } }, UserHandle.USER_ALL); } private void registerUidListener() { try { mAm.registerUidObserver(new UidObserver() { @Override public void onUidGone(int uid, boolean disabled) { mPinnerHandler.sendMessage(PooledLambda.obtainMessage( PinnerService::handleUidGone, PinnerService.this, uid)); } @Override public void onUidActive(int uid) { mPinnerHandler.sendMessage(PooledLambda.obtainMessage( PinnerService::handleUidActive, PinnerService.this, uid)); } }, UID_OBSERVER_GONE | UID_OBSERVER_ACTIVE, 0, null); } catch (RemoteException e) { Slog.e(TAG, "Failed to register uid observer", e); } } private void handleUidGone(int uid) { updateActiveState(uid, false /* active */); int key; synchronized (this) { // In case we have a pending repin, repin now. See mPendingRepin for more information. key = mPendingRepin.getOrDefault(uid, -1); if (key == -1) { return; } mPendingRepin.remove(uid); } pinApp(key, ActivityManager.getCurrentUser(), false /* force */); } private void handleUidActive(int uid) { updateActiveState(uid, true /* active */); } private void updateActiveState(int uid, boolean active) { synchronized (this) { for (int i = mPinnedApps.size() - 1; i >= 0; i--) { PinnedApp app = mPinnedApps.valueAt(i); if (app.uid == uid) { app.active = active; } } } } private void unpinApps() { ArraySet<Integer> pinKeys = getPinKeys(); for (int i = pinKeys.size() - 1; i >= 0; i--) { int key = pinKeys.valueAt(i); unpinApp(key); } } private void unpinApp(@AppKey int key) { ArrayList<PinnedFile> pinnedAppFiles; synchronized (this) { PinnedApp app = mPinnedApps.get(key); if (app == null) { return; } mPinnedApps.remove(key); pinnedAppFiles = new ArrayList<>(app.mFiles); } for (PinnedFile pinnedFile : pinnedAppFiles) { unpinFile(pinnedFile.fileName); } } private boolean isResolverActivity(ActivityInfo info) { return ResolverActivity.class.getName().equals(info.name); } public int getWebviewPinQuota() { if (!pinWebview()) { return 0; } int quota = mConfiguredWebviewPinBytes; int overrideQuota = SystemProperties.getInt("pinner.pin_webview_size", -1); if (overrideQuota != -1) { // Quota was overridden quota = overrideQuota; } return quota; } private ApplicationInfo getCameraInfo(int userHandle) { Intent cameraIntent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA); ApplicationInfo info = getApplicationInfoForIntent( cameraIntent, userHandle, false /* defaultToSystemApp */); // If the STILL_IMAGE_CAMERA intent doesn't resolve, try the _SECURE intent. // We don't use _SECURE first because it will never get set on a device // without File-based Encryption. But if the user has only set the intent // before unlocking their device, we may still be able to identify their // preference using this intent. if (info == null) { cameraIntent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE); info = getApplicationInfoForIntent( cameraIntent, userHandle, false /* defaultToSystemApp */); } // If the _SECURE intent doesn't resolve, try the original intent but request // the system app for camera if there was more than one result. if (info == null) { cameraIntent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA); info = getApplicationInfoForIntent( cameraIntent, userHandle, true /* defaultToSystemApp */); } return info; } private ApplicationInfo getHomeInfo(int userHandle) { Intent intent = mAtmInternal.getHomeIntent(); return getApplicationInfoForIntent(intent, userHandle, false); } private ApplicationInfo getAssistantInfo(int userHandle) { Intent intent = new Intent(Intent.ACTION_ASSIST); return getApplicationInfoForIntent(intent, userHandle, true); } private ApplicationInfo getApplicationInfoForIntent( Intent intent, int userHandle, boolean defaultToSystemApp) { if (intent == null) { return null; } ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivityAsUser(intent, MATCH_FLAGS, userHandle); // If this intent can resolve to only one app, choose that one. // Otherwise, if we've requested to default to the system app, return it; // if we have not requested that default, return null if there's more than one option. // If there's more than one system app, return null since we don't know which to pick. if (resolveInfo == null) { return null; } if (!isResolverActivity(resolveInfo.activityInfo)) { return resolveInfo.activityInfo.applicationInfo; } if (defaultToSystemApp) { List<ResolveInfo> infoList = mContext.getPackageManager().queryIntentActivitiesAsUser( intent, MATCH_FLAGS, userHandle); ApplicationInfo systemAppInfo = null; for (ResolveInfo info : infoList) { if ((info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { if (systemAppInfo == null) { systemAppInfo = info.activityInfo.applicationInfo; } else { // If there's more than one system app, return null due to ambiguity. return null; } } } return systemAppInfo; } return null; } private void sendPinAppsMessage(int userHandle) { mPinnerHandler.sendMessage( PooledLambda.obtainMessage(PinnerService::pinApps, this, userHandle)); } private void sendPinAppsWithUpdatedKeysMessage(int userHandle) { mPinnerHandler.sendMessage(PooledLambda.obtainMessage( PinnerService::pinAppsWithUpdatedKeys, this, userHandle)); } private void sendUnpinAppsMessage() { mPinnerHandler.sendMessage(PooledLambda.obtainMessage(PinnerService::unpinApps, this)); } private ArraySet<Integer> createPinKeys() { ArraySet<Integer> pinKeys = new ArraySet<>(); // Pin the camera application. Default to the system property only if the experiment // phenotype property is not set. boolean shouldPinCamera = mConfiguredToPinCamera && mDeviceConfigInterface.getBoolean(DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT, "pin_camera", SystemProperties.getBoolean("pinner.pin_camera", true)); if (shouldPinCamera) { pinKeys.add(KEY_CAMERA); } else if (DEBUG) { Slog.i(TAG, "Pinner - skip pinning camera app"); } if (mConfiguredHomePinBytes > 0) { pinKeys.add(KEY_HOME); } if (mConfiguredToPinAssistant) { pinKeys.add(KEY_ASSISTANT); } return pinKeys; } private synchronized ArraySet<Integer> getPinKeys() { return mPinKeys; } private void pinApps(int userHandle) { pinAppsInternal(userHandle, false); } private void pinAppsWithUpdatedKeys(int userHandle) { pinAppsInternal(userHandle, true); } /** * @param updateKeys True if the pinned app list has to be updated. This is true only when * "pinner repin" shell command is requested. */ private void pinAppsInternal(int userHandle, boolean updateKeys) { if (updateKeys) { ArraySet<Integer> newKeys = createPinKeys(); synchronized (this) { // This code path demands preceding unpinApps() call. if (!mPinnedApps.isEmpty()) { Slog.e(TAG, "Attempted to update a list of apps, " + "but apps were already pinned. Skipping."); return; } mPinKeys = newKeys; } } ArraySet<Integer> currentPinKeys = getPinKeys(); for (int i = currentPinKeys.size() - 1; i >= 0; i--) { int key = currentPinKeys.valueAt(i); pinApp(key, userHandle, true /* force */); } } /** * @see #pinApp(int, int, boolean) */ private void sendPinAppMessage(int key, int userHandle, boolean force) { mPinnerHandler.sendMessage( PooledLambda.obtainMessage(PinnerService::pinApp, this, key, userHandle, force)); } /** * Pins an app of a specific type {@code key}. * * @param force If false, this will not repin the app if it's currently active. See * {@link #mPendingRepin}. */ private void pinApp(int key, int userHandle, boolean force) { int uid = getUidForKey(key); // In case the app is currently active, don't repin until next process restart. See // mPendingRepin for more information. if (!force && uid != -1) { synchronized (this) { mPendingRepin.put(uid, key); } return; } ApplicationInfo info = getInfoForKey(key, userHandle); unpinApp(key); if (info != null) { pinAppInternal(key, info); } } /** * Checks whether the pinned package with {@code key} is active or not. * @return The uid of the pinned app, or {@code -1} otherwise. */ private int getUidForKey(@AppKey int key) { synchronized (this) { PinnedApp existing = mPinnedApps.get(key); return existing != null && existing.active ? existing.uid : -1; } } /** * Retrieves the current application info for the given app type. * * @param key The app type to retrieve the info for. * @param userHandle The user id of the current user. */ private @Nullable ApplicationInfo getInfoForKey(@AppKey int key, int userHandle) { switch (key) { case KEY_CAMERA: return getCameraInfo(userHandle); case KEY_HOME: return getHomeInfo(userHandle); case KEY_ASSISTANT: return getAssistantInfo(userHandle); default: return null; } } /** * @return The app type name for {@code key}. */ private String getNameForKey(@AppKey int key) { switch (key) { case KEY_CAMERA: return "Camera"; case KEY_HOME: return "Home"; case KEY_ASSISTANT: return "Assistant"; default: return ""; } } /** * Handle any changes in the anon region pinner config. */ private void refreshPinAnonConfig() { long newPinAnonSize = mDeviceConfigInterface.getLong( DEVICE_CONFIG_NAMESPACE_ANON_SIZE, DEVICE_CONFIG_KEY_ANON_SIZE, DEFAULT_ANON_SIZE); newPinAnonSize = Math.max(0, Math.min(newPinAnonSize, MAX_ANON_SIZE)); if (newPinAnonSize != mPinAnonSize) { mPinAnonSize = newPinAnonSize; pinAnonRegion(); } } /** * Pin an empty anonymous region. This should only be used for ablation experiments. */ private void pinAnonRegion() { if (mPinAnonSize == 0) { Slog.d(TAG, "pinAnonRegion: releasing pinned region"); unpinAnonRegion(); return; } long alignedPinSize = mPinAnonSize; if (alignedPinSize % PAGE_SIZE != 0) { alignedPinSize -= alignedPinSize % PAGE_SIZE; Slog.e(TAG, "pinAnonRegion: aligning size to " + alignedPinSize); } if (mPinAnonAddress != 0) { if (mCurrentlyPinnedAnonSize == alignedPinSize) { Slog.d(TAG, "pinAnonRegion: already pinned region of size " + alignedPinSize); return; } Slog.d(TAG, "pinAnonRegion: resetting pinned region for new size " + alignedPinSize); unpinAnonRegion(); } long address = 0; try { // Map as SHARED to avoid changing rss.anon for system_server (per /proc/*/status). // The mapping is visible in other rss metrics, and as private dirty in smaps/meminfo. address = Os.mmap(0, alignedPinSize, OsConstants.PROT_READ | OsConstants.PROT_WRITE, OsConstants.MAP_SHARED | OsConstants.MAP_ANONYMOUS, new FileDescriptor(), /*offset=*/0); Unsafe tempUnsafe = null; Class<sun.misc.Unsafe> clazz = sun.misc.Unsafe.class; for (java.lang.reflect.Field f : clazz.getDeclaredFields()) { f.setAccessible(true); Object obj = f.get(null); if (clazz.isInstance(obj)) { tempUnsafe = clazz.cast(obj); } } if (tempUnsafe == null) { throw new Exception("Couldn't get Unsafe"); } Method setMemory = clazz.getMethod("setMemory", long.class, long.class, byte.class); setMemory.invoke(tempUnsafe, address, alignedPinSize, (byte) 1); Os.mlock(address, alignedPinSize); mCurrentlyPinnedAnonSize = alignedPinSize; mPinAnonAddress = address; address = -1; Slog.w(TAG, "pinAnonRegion success, size=" + mCurrentlyPinnedAnonSize); } catch (Exception ex) { Slog.e(TAG, "Could not pin anon region of size " + alignedPinSize, ex); return; } finally { if (address >= 0) { PinnerUtils.safeMunmap(address, alignedPinSize); } } } private void unpinAnonRegion() { if (mPinAnonAddress != 0) { PinnerUtils.safeMunmap(mPinAnonAddress, mCurrentlyPinnedAnonSize); } mPinAnonAddress = 0; mCurrentlyPinnedAnonSize = 0; } /** * @return The maximum amount of bytes to be pinned for an app of type {@code key}. */ private int getSizeLimitForKey(@AppKey int key) { switch (key) { case KEY_CAMERA: return mConfiguredCameraPinBytes; case KEY_HOME: return mConfiguredHomePinBytes; case KEY_ASSISTANT: return mConfiguredAssistantPinBytes; default: return 0; } } /** * Retrieves remaining quota for pinner service, once it reaches 0 it will no longer * pin any file. */ private long getAvailableGlobalQuota() { return mConfiguredMaxPinnedMemory - mCurrentPinnedMemory; } /** * Pins an application. * * @param key The key of the app to pin. * @param appInfo The corresponding app info. */ private void pinAppInternal(@AppKey int key, @Nullable ApplicationInfo appInfo) { if (appInfo == null) { return; } PinnedApp pinnedApp = new PinnedApp(appInfo); synchronized (this) { mPinnedApps.put(key, pinnedApp); } // pin APK final int pinSizeLimit = getSizeLimitForKey(key); List<String> apks = new ArrayList<>(); apks.add(appInfo.sourceDir); if (appInfo.splitSourceDirs != null) { for (String splitApk : appInfo.splitSourceDirs) { apks.add(splitApk); } } long apkPinSizeLimit = pinSizeLimit; for (String apk : apks) { if (apkPinSizeLimit <= 0) { Slog.w(TAG, "Reached to the pin size limit. Skipping: " + apk); // Continue instead of break to print all skipped APK names. continue; } String pinGroup = getNameForKey(key); boolean shouldPinDeps = apk.equals(appInfo.sourceDir); PinnedFile pf = pinFile(apk, apkPinSizeLimit, appInfo, pinGroup, shouldPinDeps); if (pf == null) { Slog.e(TAG, "Failed to pin " + apk); continue; } if (DEBUG) { Slog.i(TAG, "Pinned " + pf.fileName); } synchronized (this) { pinnedApp.mFiles.add(pf); } apkPinSizeLimit -= pf.bytesPinned; } } /** * Pin file or apk to memory. * * Prefer to use this method instead of {@link #pinFileInternal(String, int, boolean)} as it * takes care of accounting and if pinning an apk, it also pins any extra optimized art files * that related to the file but not within itself. * * @param fileToPin File to pin * @param bytesRequestedToPin maximum bytes requested to pin for {@code fileToPin}. * @param pinOptimizedDeps whether optimized dependencies such as odex,vdex, etc be pinned. * Note: {@code bytesRequestedToPin} limit will not apply to optimized * dependencies pinned, only global quotas will apply instead. * @return pinned file */ public PinnedFile pinFile(String fileToPin, long bytesRequestedToPin, @Nullable ApplicationInfo appInfo, @Nullable String groupName, boolean pinOptimizedDeps) { PinnedFile existingPin; synchronized (this) { existingPin = mPinnedFiles.get(fileToPin); } if (existingPin != null) { if (existingPin.bytesPinned == bytesRequestedToPin) { // Duplicate pin requesting same amount of bytes, lets just bail out. return null; } else { // User decided to pin a different amount of bytes than currently pinned // so this is a valid pin request. Unpin the previous version before repining. if (DEBUG) { Slog.d(TAG, "Unpinning file prior to repin: " + fileToPin); } unpinFile(fileToPin); } } long remainingQuota = getAvailableGlobalQuota(); if (pinGlobalQuota()) { if (remainingQuota <= 0) { Slog.w(TAG, "Reached pin quota, skipping file: " + fileToPin); return null; } bytesRequestedToPin = Math.min(bytesRequestedToPin, remainingQuota); } boolean isApk = fileToPin.endsWith(".apk"); PinnedFile pf = mInjector.pinFileInternal(this, fileToPin, bytesRequestedToPin, /*attemptPinIntrospection=*/isApk); if (pf == null) { Slog.e(TAG, "Failed to pin file = " + fileToPin); return null; } pf.groupName = groupName != null ? groupName : ""; mCurrentPinnedMemory += pf.bytesPinned; synchronized (this) { mPinnedFiles.put(pf.fileName, pf); } if (pinOptimizedDeps) { mCurrentPinnedMemory += pinOptimizedDexDependencies(pf, getAvailableGlobalQuota(), appInfo); } return pf; } /** * Pin any dependency optimized files generated by ART. * @param pinnedFile An already pinned file whose dependencies we want pinned. * @param maxBytesToPin Maximum amount of bytes to pin. * @param appInfo Used to determine the ABI in case the application has one custom set, when set * to null it will use the default supported ABI by the device. * @return total bytes pinned. */ private long pinOptimizedDexDependencies( PinnedFile pinnedFile, long maxBytesToPin, @Nullable ApplicationInfo appInfo) { if (pinnedFile == null) { return 0; } long bytesPinned = 0; if (pinnedFile.fileName.endsWith(".jar") | pinnedFile.fileName.endsWith(".apk")) { String abi = null; if (appInfo != null) { abi = appInfo.primaryCpuAbi; } if (abi == null) { abi = Build.SUPPORTED_ABIS[0]; } // Check whether the runtime has compilation artifacts to pin. String arch = VMRuntime.getInstructionSet(abi); String[] files = null; try { files = DexFile.getDexFileOutputPaths(pinnedFile.fileName, arch); } catch (IOException ioe) { } if (files == null) { return bytesPinned; } for (String file : files) { // Unpin if it was already pinned prior to re-pinning. unpinFile(file); PinnedFile df = mInjector.pinFileInternal(this, file, maxBytesToPin, /*attemptPinIntrospection=*/false); if (df == null) { Slog.i(TAG, "Failed to pin ART file = " + file); return bytesPinned; } df.groupName = pinnedFile.groupName; pinnedFile.pinnedDeps.add(df); maxBytesToPin -= df.bytesPinned; bytesPinned += df.bytesPinned; synchronized (this) { mPinnedFiles.put(df.fileName, df); } } } return bytesPinned; } /** * mlock length bytes of fileToPin in memory * * If attemptPinIntrospection is true, then treat the file to pin as a zip file and * look for a "pinlist.meta" file in the archive root directory. The structure of this * file is a PINLIST_META as described below: * * <pre> * PINLIST_META: PIN_RANGE* * PIN_RANGE: PIN_START PIN_LENGTH * PIN_START: big endian i32: offset in bytes of pin region from file start * PIN_LENGTH: big endian i32: length of pin region in bytes * </pre> * * (We use big endian because that's what DataInputStream is hardcoded to use.) * * If attemptPinIntrospection is false, then we use a single implicit PIN_RANGE of (0, * maxBytesToPin); that is, we attempt to pin the first maxBytesToPin bytes of the file. * * After we open a file, we march through the list of pin ranges and attempt to pin * each one, stopping after we've pinned maxBytesToPin bytes. (We may truncate the last * pinned range to fit.) In this way, by choosing to emit certain PIN_RANGE pairs * before others, file generators can express pins in priority order, making most * effective use of the pinned-page quota. * * N.B. Each PIN_RANGE is clamped to the actual bounds of the file; all inputs have a * meaningful interpretation. Also, a range locking a single byte of a page locks the * whole page. Any truncated PIN_RANGE at EOF is ignored. Overlapping pinned entries * are legal, but each pin of a byte counts toward the pin quota regardless of whether * that byte has already been pinned, so the generator of PINLIST_META ought to ensure * that ranges are non-overlapping. * * @param fileToPin Path to file to pin * @param maxBytesToPin Maximum number of bytes to pin * @param attemptPinIntrospection If true, try to open file as a * zip in order to extract the * @return Pinned memory resource owner thing or null on error */ private PinnedFile pinFileInternal( String fileToPin, long maxBytesToPin, boolean attemptPinIntrospection) { if (DEBUG) { Slog.d(TAG, "pin file: " + fileToPin + " use-pinlist: " + attemptPinIntrospection); } ZipFile fileAsZip = null; InputStream pinRangeStream = null; try { if (attemptPinIntrospection) { fileAsZip = maybeOpenZip(fileToPin); } if (fileAsZip != null) { pinRangeStream = maybeOpenPinMetaInZip(fileAsZip, fileToPin); } boolean use_pinlist = (pinRangeStream != null); PinRangeSource pinRangeSource = use_pinlist ? new PinRangeSourceStream(pinRangeStream) : new PinRangeSourceStatic(0, Integer.MAX_VALUE /* will be clipped */); PinnedFile pinnedFile = pinFileRanges(fileToPin, maxBytesToPin, pinRangeSource); if (pinnedFile != null) { pinnedFile.used_pinlist = use_pinlist; } return pinnedFile; } finally { PinnerUtils.safeClose(pinRangeStream); PinnerUtils.safeClose(fileAsZip); // Also closes any streams we've opened } } /** * Attempt to open a file as a zip file. On any sort of corruption, log, swallow the * error, and return null. */ private static ZipFile maybeOpenZip(String fileName) { ZipFile zip = null; try { zip = new ZipFile(fileName); } catch (IOException ex) { Slog.w(TAG, String.format("could not open \"%s\" as zip: pinning as blob", fileName), ex); } return zip; } /** * Open a pin metadata file in the zip if one is present. * * @param zipFile Zip file to search * @return Open input stream or null on any error */ private static InputStream maybeOpenPinMetaInZip(ZipFile zipFile, String fileName) { if (!PROP_PIN_PINLIST) { if (DEBUG) { Slog.i(TAG, "Pin - skip pinlist.meta in " + fileName); } return null; } // Looking at root directory is the old behavior but still some apps rely on it so keeping // for backward compatibility. As doing a single item lookup is cheap in the root. ZipEntry pinMetaEntry = zipFile.getEntry(PIN_META_FILENAME); if (pinMetaEntry == null) { // It is usually within an apk's control to include files in assets/ directory // so this would be the expected point to have the pinlist.meta coming from. // we explicitly avoid doing an exhaustive search because it may be expensive so // prefer to have a good known location to retrieve the file. pinMetaEntry = zipFile.getEntry("assets/" + PIN_META_FILENAME); } InputStream pinMetaStream = null; if (pinMetaEntry != null) { if (DEBUG) { Slog.d(TAG, "Found pinlist.meta for " + fileName); } try { pinMetaStream = zipFile.getInputStream(pinMetaEntry); } catch (IOException ex) { Slog.w(TAG, String.format( "error reading pin metadata \"%s\": pinning as blob", fileName), ex); } } else { Slog.w(TAG, String.format( "Could not find pinlist.meta for \"%s\": pinning as blob", fileName)); } return pinMetaStream; } /** * Helper for pinFile. * * @param fileToPin Name of file to pin * @param maxBytesToPin Maximum number of bytes to pin * @param pinRangeSource Read PIN_RANGE entries from this stream to tell us what bytes * to pin. * @return PinnedFile or null on error */ private static PinnedFile pinFileRanges( String fileToPin, long maxBytesToPin, PinRangeSource pinRangeSource) { FileDescriptor fd = new FileDescriptor(); long address = -1; long mapSize = 0; try { int openFlags = (OsConstants.O_RDONLY | OsConstants.O_CLOEXEC); fd = Os.open(fileToPin, openFlags, 0); mapSize = (int) Math.min(Os.fstat(fd).st_size, Integer.MAX_VALUE); address = Os.mmap( 0, mapSize, OsConstants.PROT_READ, OsConstants.MAP_SHARED, fd, /*offset=*/0); PinRange pinRange = new PinRange(); long bytesPinned = 0; // We pin at page granularity, so make sure the limit is page-aligned if (maxBytesToPin % PAGE_SIZE != 0) { maxBytesToPin -= maxBytesToPin % PAGE_SIZE; } while (bytesPinned < maxBytesToPin && pinRangeSource.read(pinRange)) { long pinStart = pinRange.start; long pinLength = pinRange.length; pinStart = PinnerUtils.clamp(0, pinStart, mapSize); pinLength = PinnerUtils.clamp(0, pinLength, mapSize - pinStart); pinLength = Math.min(maxBytesToPin - bytesPinned, pinLength); // mlock doesn't require the region to be page-aligned, but we snap the // lock region to page boundaries anyway so that we don't under-count // locking a single byte of a page as a charge of one byte even though the // OS will retain the whole page. Thanks to this adjustment, we slightly // over-count the pin charge of back-to-back pins touching the same page, // but better that than undercounting. Besides: nothing stops pin metafile // creators from making the actual regions page-aligned. pinLength += pinStart % PAGE_SIZE; pinStart -= pinStart % PAGE_SIZE; if (pinLength % PAGE_SIZE != 0) { pinLength += PAGE_SIZE - pinLength % PAGE_SIZE; } pinLength = PinnerUtils.clamp(0, pinLength, maxBytesToPin - bytesPinned); if (pinLength > 0) { if (DEBUG) { Slog.d(TAG, String.format("pinning at %s %s bytes of %s", pinStart, pinLength, fileToPin)); } Os.mlock(address + pinStart, pinLength); } bytesPinned += pinLength; } PinnedFile pinnedFile = new PinnedFile(address, mapSize, fileToPin, bytesPinned); address = -1; // Ownership transferred return pinnedFile; } catch (ErrnoException ex) { Slog.e(TAG, "Could not pin file " + fileToPin, ex); return null; } finally { PinnerUtils.safeClose(fd); if (address >= 0) { PinnerUtils.safeMunmap(address, mapSize); } } } private List<PinnedFile> getAllPinsForGroup(String group) { List<PinnedFile> filesInGroup; synchronized (this) { filesInGroup = mPinnedFiles.values() .stream() .filter(pf -> pf.groupName.equals(group)) .toList(); } return filesInGroup; } public void unpinGroup(String group) { List<PinnedFile> pinnedFiles = getAllPinsForGroup(group); for (PinnedFile pf : pinnedFiles) { unpinFile(pf.fileName); } } /** * Unpin a file and its optimized dependencies. * * @param filename file to unpin. * @return number of bytes unpinned, 0 in case of failure or nothing to unpin. */ public long unpinFile(String filename) { PinnedFile pinnedFile; synchronized (this) { pinnedFile = mPinnedFiles.get(filename); } if (pinnedFile == null) { // File not pinned, nothing to do. return 0; } long unpinnedBytes = pinnedFile.bytesPinned; pinnedFile.close(); synchronized (this) { if (DEBUG) { Slog.d(TAG, "Unpinned file: " + filename); } mCurrentPinnedMemory -= pinnedFile.bytesPinned; mPinnedFiles.remove(pinnedFile.fileName); for (PinnedFile dep : pinnedFile.pinnedDeps) { if (dep == null) { continue; } unpinnedBytes -= dep.bytesPinned; mCurrentPinnedMemory -= dep.bytesPinned; mPinnedFiles.remove(dep.fileName); if (DEBUG) { Slog.d(TAG, "Unpinned dependency: " + dep.fileName); } } } return unpinnedBytes; } public List<PinnedFileStat> getPinnerStats() { ArrayList<PinnedFileStat> stats = new ArrayList<>(); Collection<PinnedFile> pinnedFiles; synchronized (this) { pinnedFiles = mPinnedFiles.values(); } for (PinnedFile pf : pinnedFiles) { PinnedFileStat stat = new PinnedFileStat(pf.fileName, pf.bytesPinned, pf.groupName); stats.add(stat); } if (mCurrentlyPinnedAnonSize > 0) { stats.add(new PinnedFileStat( ANON_REGION_STAT_NAME, mCurrentlyPinnedAnonSize, ANON_REGION_STAT_NAME)); } return stats; } public final class BinderService extends IPinnerService.Stub { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; HashSet<PinnedFile> shownPins = new HashSet<>(); HashSet<String> shownGroups = new HashSet<>(); HashSet<String> groupsToPrint = new HashSet<>(); final double bytesPerMB = 1024 * 1024; pw.format("Pinner Configs:\n"); pw.format(" Total Pinner quota: %d%% of total device memory\n", mConfiguredMaxPinnedMemoryPercentage); pw.format(" Maximum Pinner quota: %d bytes (%.2f MB)\n", mConfiguredMaxPinnedMemory, mConfiguredMaxPinnedMemory / bytesPerMB); pw.format(" Max Home App Pin Bytes (without deps): %d (%.2f MB)\n", mConfiguredHomePinBytes, mConfiguredHomePinBytes / bytesPerMB); pw.format(" Max Assistant App Pin Bytes (without deps): %d (%.2f MB)\n", mConfiguredAssistantPinBytes, mConfiguredAssistantPinBytes / bytesPerMB); pw.format( " Max Camera App Pin Bytes (without deps): %d (%.2f MB)\n", mConfiguredCameraPinBytes, mConfiguredCameraPinBytes / bytesPerMB); pw.format("\nPinned Files:\n"); synchronized (PinnerService.this) { long totalSize = 0; // We print apps separately from regular pins as they contain extra information that // other pins do not. for (int key : mPinnedApps.keySet()) { PinnedApp app = mPinnedApps.get(key); pw.print(getNameForKey(key)); pw.print(" uid="); pw.print(app.uid); pw.print(" active="); pw.print(app.active); if (!app.mFiles.isEmpty()) { shownGroups.add(app.mFiles.getFirst().groupName); } pw.println(); long bytesPinnedForApp = 0; long bytesPinnedForAppDeps = 0; for (PinnedFile pf : mPinnedApps.get(key).mFiles) { pw.print(" "); pw.format("%s pinned:%d bytes (%.2f MB) pinlist:%b\n", pf.fileName, pf.bytesPinned, pf.bytesPinned / bytesPerMB, pf.used_pinlist); totalSize += pf.bytesPinned; bytesPinnedForApp += pf.bytesPinned; shownPins.add(pf); for (PinnedFile dep : pf.pinnedDeps) { pw.print(" "); pw.format("%s pinned:%d bytes (%.2f MB) pinlist:%b (Dependency)\n", dep.fileName, dep.bytesPinned, dep.bytesPinned / bytesPerMB, dep.used_pinlist); totalSize += dep.bytesPinned; bytesPinnedForAppDeps += dep.bytesPinned; shownPins.add(dep); } } long bytesPinnedForAppAndDeps = bytesPinnedForApp + bytesPinnedForAppDeps; pw.format("Total Pinned = %d (%.2f MB) [App=%d (%.2f MB), " + "Dependencies=%d (%.2f MB)]\n\n", bytesPinnedForAppAndDeps, bytesPinnedForAppAndDeps / bytesPerMB, bytesPinnedForApp, bytesPinnedForApp / bytesPerMB, bytesPinnedForAppDeps, bytesPinnedForAppDeps / bytesPerMB); } pw.println(); for (PinnedFile pinnedFile : mPinnedFiles.values()) { if (!groupsToPrint.contains(pinnedFile.groupName) && !shownGroups.contains(pinnedFile.groupName)) { groupsToPrint.add(pinnedFile.groupName); } } // Print all the non app groups. for (String group : groupsToPrint) { List<PinnedFile> groupPins = getAllPinsForGroup(group); pw.print("\nGroup:" + group); long bytesPinnedForGroupNoDeps = 0; long bytesPinnedForGroupDeps = 0; pw.println(); for (PinnedFile pinnedFile : groupPins) { if (shownPins.contains(pinnedFile)) { // Already displayed and accounted for, skip. continue; } pw.format(" %s pinned: %d bytes (%.2f MB) pinlist:%b\n", pinnedFile.fileName, pinnedFile.bytesPinned, pinnedFile.bytesPinned / bytesPerMB, pinnedFile.used_pinlist); totalSize += pinnedFile.bytesPinned; bytesPinnedForGroupNoDeps += pinnedFile.bytesPinned; shownPins.add(pinnedFile); for (PinnedFile dep : pinnedFile.pinnedDeps) { if (shownPins.contains(dep)) { // Already displayed and accounted for, skip. continue; } pw.print(" "); pw.format("%s pinned:%d bytes (%.2f MB) pinlist:%b (Dependency)\n", dep.fileName, dep.bytesPinned, dep.bytesPinned / bytesPerMB, dep.used_pinlist); totalSize += dep.bytesPinned; bytesPinnedForGroupDeps += dep.bytesPinned; shownPins.add(dep); } } long bytesPinnedForGroup = bytesPinnedForGroupNoDeps + bytesPinnedForGroupDeps; pw.format("Total Pinned = %d (%.2f MB) [Main=%d (%.2f MB), " + "Dependencies=%d (%.2f MB)]\n\n", bytesPinnedForGroup, bytesPinnedForGroup / bytesPerMB, bytesPinnedForGroupNoDeps, bytesPinnedForGroupNoDeps / bytesPerMB, bytesPinnedForGroupDeps, bytesPinnedForGroupDeps / bytesPerMB); } pw.println(); if (mPinAnonAddress != 0) { pw.format("Pinned anon region: %d (%.2f MB)\n", mCurrentlyPinnedAnonSize, mCurrentlyPinnedAnonSize / bytesPerMB); totalSize += mCurrentlyPinnedAnonSize; } pw.format("Total pinned: %d bytes (%.2f MB)\n", totalSize, totalSize / bytesPerMB); pw.format("Available Pinner quota: %d bytes (%.2f MB)\n", getAvailableGlobalQuota(), getAvailableGlobalQuota() / bytesPerMB); pw.println(); if (!mPendingRepin.isEmpty()) { pw.print("Pending repin: "); for (int key : mPendingRepin.values()) { pw.print(getNameForKey(key)); pw.print(' '); } pw.println(); } } } private void repin() { sendUnpinAppsMessage(); // TODO(morrita): Consider supporting non-system user. sendPinAppsWithUpdatedKeysMessage(UserHandle.USER_SYSTEM); } private void printError(FileDescriptor out, String message) { PrintWriter writer = new PrintWriter(new FileOutputStream(out)); writer.println(message); writer.flush(); } @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver) { if (args.length < 1) { printError(out, "Command is not given."); resultReceiver.send(-1, null); return; } String command = args[0]; switch (command) { case "repin": repin(); break; default: printError(out, String.format("Unknown pinner command: %s. Supported commands: repin", command)); resultReceiver.send(-1, null); return; } resultReceiver.send(0, null); } @EnforcePermission(android.Manifest.permission.DUMP) @Override public List<PinnedFileStat> getPinnerStats() { getPinnerStats_enforcePermission(); return PinnerService.this.getPinnerStats(); } } final static class PinRange { int start; int length; } /** * Represents an app that was pinned. */ private final class PinnedApp { /** * The uid of the package being pinned. This stays constant while the package stays * installed. */ final int uid; /** Whether it is currently active, i.e. there is a running process from that package. */ boolean active; /** List of pinned files. */ final ArrayList<PinnedFile> mFiles = new ArrayList<>(); private PinnedApp(ApplicationInfo appInfo) { uid = appInfo.uid; active = mAmInternal.isUidActive(uid); } } final class PinnerHandler extends Handler { static final int PIN_ONSTART_MSG = 4001; public PinnerHandler(Looper looper) { super(looper, null, true); } @Override public void handleMessage(Message msg) { switch (msg.what) { case PIN_ONSTART_MSG: { handlePinOnStart(); } break; default: super.handleMessage(msg); } } } } 为什么launcher的odex文件没有被pin >adb wait-for-device && adb logcat -s PinnerService:V *:S --------- beginning of system 01-04 03:15:02.848 3245 3315 W PinnerService: Could not find pinlist.meta for "/system_ext/priv-app/OplusLauncher/OplusLauncher.apk": pinning as blob
11-11
// Core algorithmic facilities -*- C++ -*- // Copyright (C) 2001-2014 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // Under Section 7 of GPL version 3, you are granted additional // permissions described in the GCC Runtime Library Exception, version // 3.1, as published by the Free Software Foundation. // You should have received a copy of the GNU General Public License and // a copy of the GCC Runtime Library Exception along with this program; // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // <http://www.gnu.org/licenses/>. /* * * Copyright (c) 1994 * Hewlett-Packard Company * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Hewlett-Packard Company makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * * * Copyright (c) 1996-1998 * Silicon Graphics Computer Systems, Inc. * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Silicon Graphics makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. */ /** @file bits/stl_algobase.h * This is an internal header file, included by other library headers. * Do not attempt to use it directly. @headername{algorithm} */ #ifndef _STL_ALGOBASE_H #define _STL_ALGOBASE_H 1 #include <bits/c++config.h> #include <bits/functexcept.h> #include <bits/cpp_type_traits.h> #include <ext/type_traits.h> #include <ext/numeric_traits.h> #include <bits/stl_pair.h> #include <bits/stl_iterator_base_types.h> #include <bits/stl_iterator_base_funcs.h> #include <bits/stl_iterator.h> #include <bits/concept_check.h> #include <debug/debug.h> #include <bits/move.h> // For std::swap and _GLIBCXX_MOVE #include <bits/predefined_ops.h> namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus < 201103L // See http://gcc.gnu.org/ml/libstdc++/2004-08/msg00167.html: in a // nutshell, we are partially implementing the resolution of DR 187, // when it's safe, i.e., the value_types are equal. template<bool _BoolType> struct __iter_swap { template<typename _ForwardIterator1, typename _ForwardIterator2> static void iter_swap(_ForwardIterator1 __a, _ForwardIterator2 __b) { typedef typename iterator_traits<_ForwardIterator1>::value_type _ValueType1; _ValueType1 __tmp = _GLIBCXX_MOVE(*__a); *__a = _GLIBCXX_MOVE(*__b); *__b = _GLIBCXX_MOVE(__tmp); } }; template<> struct __iter_swap<true> { template<typename _ForwardIterator1, typename _ForwardIterator2> static void iter_swap(_ForwardIterator1 __a, _ForwardIterator2 __b) { swap(*__a, *__b); } }; #endif /** * @brief Swaps the contents of two iterators. * @ingroup mutating_algorithms * @param __a An iterator. * @param __b Another iterator. * @return Nothing. * * This function swaps the values pointed to by two iterators, not the * iterators themselves. */ template<typename _ForwardIterator1, typename _ForwardIterator2> inline void iter_swap(_ForwardIterator1 __a, _ForwardIterator2 __b) { // concept requirements __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< _ForwardIterator1>) __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< _ForwardIterator2>) #if __cplusplus < 201103L typedef typename iterator_traits<_ForwardIterator1>::value_type _ValueType1; typedef typename iterator_traits<_ForwardIterator2>::value_type _ValueType2; __glibcxx_function_requires(_ConvertibleConcept<_ValueType1, _ValueType2>) __glibcxx_function_requires(_ConvertibleConcept<_ValueType2, _ValueType1>) typedef typename iterator_traits<_ForwardIterator1>::reference _ReferenceType1; typedef typename iterator_traits<_ForwardIterator2>::reference _ReferenceType2; std::__iter_swap<__are_same<_ValueType1, _ValueType2>::__value && __are_same<_ValueType1&, _ReferenceType1>::__value && __are_same<_ValueType2&, _ReferenceType2>::__value>:: iter_swap(__a, __b); #else swap(*__a, *__b); #endif } /** * @brief Swap the elements of two sequences. * @ingroup mutating_algorithms * @param __first1 A forward iterator. * @param __last1 A forward iterator. * @param __first2 A forward iterator. * @return An iterator equal to @p first2+(last1-first1). * * Swaps each element in the range @p [first1,last1) with the * corresponding element in the range @p [first2,(last1-first1)). * The ranges must not overlap. */ template<typename _ForwardIterator1, typename _ForwardIterator2> _ForwardIterator2 swap_ranges(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) { // concept requirements __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< _ForwardIterator1>) __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< _ForwardIterator2>) __glibcxx_requires_valid_range(__first1, __last1); for (; __first1 != __last1; ++__first1, ++__first2) std::iter_swap(__first1, __first2); return __first2; } /** * @brief This does what you think it does. * @ingroup sorting_algorithms * @param __a A thing of arbitrary type. * @param __b Another thing of arbitrary type. * @return The lesser of the parameters. * * This is the simple classic generic implementation. It will work on * temporary expressions, since they are only evaluated once, unlike a * preprocessor macro. */ template<typename _Tp> inline const _Tp& min(const _Tp& __a, const _Tp& __b) { // concept requirements __glibcxx_function_requires(_LessThanComparableConcept<_Tp>) //return __b < __a ? __b : __a; if (__b < __a) return __b; return __a; } /** * @brief This does what you think it does. * @ingroup sorting_algorithms * @param __a A thing of arbitrary type. * @param __b Another thing of arbitrary type. * @return The greater of the parameters. * * This is the simple classic generic implementation. It will work on * temporary expressions, since they are only evaluated once, unlike a * preprocessor macro. */ template<typename _Tp> inline const _Tp& max(const _Tp& __a, const _Tp& __b) { // concept requirements __glibcxx_function_requires(_LessThanComparableConcept<_Tp>) //return __a < __b ? __b : __a; if (__a < __b) return __b; return __a; } /** * @brief This does what you think it does. * @ingroup sorting_algorithms * @param __a A thing of arbitrary type. * @param __b Another thing of arbitrary type. * @param __comp A @link comparison_functors comparison functor@endlink. * @return The lesser of the parameters. * * This will work on temporary expressions, since they are only evaluated * once, unlike a preprocessor macro. */ template<typename _Tp, typename _Compare> inline const _Tp& min(const _Tp& __a, const _Tp& __b, _Compare __comp) { //return __comp(__b, __a) ? __b : __a; if (__comp(__b, __a)) return __b; return __a; } /** * @brief This does what you think it does. * @ingroup sorting_algorithms * @param __a A thing of arbitrary type. * @param __b Another thing of arbitrary type. * @param __comp A @link comparison_functors comparison functor@endlink. * @return The greater of the parameters. * * This will work on temporary expressions, since they are only evaluated * once, unlike a preprocessor macro. */ template<typename _Tp, typename _Compare> inline const _Tp& max(const _Tp& __a, const _Tp& __b, _Compare __comp) { //return __comp(__a, __b) ? __b : __a; if (__comp(__a, __b)) return __b; return __a; } // If _Iterator is a __normal_iterator return its base (a plain pointer, // normally) otherwise return it untouched. See copy, fill, ... template<typename _Iterator> struct _Niter_base : _Iter_base<_Iterator, __is_normal_iterator<_Iterator>::__value> { }; template<typename _Iterator> inline typename _Niter_base<_Iterator>::iterator_type __niter_base(_Iterator __it) { return std::_Niter_base<_Iterator>::_S_base(__it); } // Likewise, for move_iterator. template<typename _Iterator> struct _Miter_base : _Iter_base<_Iterator, __is_move_iterator<_Iterator>::__value> { }; template<typename _Iterator> inline typename _Miter_base<_Iterator>::iterator_type __miter_base(_Iterator __it) { return std::_Miter_base<_Iterator>::_S_base(__it); } // All of these auxiliary structs serve two purposes. (1) Replace // calls to copy with memmove whenever possible. (Memmove, not memcpy, // because the input and output ranges are permitted to overlap.) // (2) If we're using random access iterators, then write the loop as // a for loop with an explicit count. template<bool, bool, typename> struct __copy_move { template<typename _II, typename _OI> static _OI __copy_m(_II __first, _II __last, _OI __result) { for (; __first != __last; ++__result, ++__first) *__result = *__first; return __result; } }; #if __cplusplus >= 201103L template<typename _Category> struct __copy_move<true, false, _Category> { template<typename _II, typename _OI> static _OI __copy_m(_II __first, _II __last, _OI __result) { for (; __first != __last; ++__result, ++__first) *__result = std::move(*__first); return __result; } }; #endif template<> struct __copy_move<false, false, random_access_iterator_tag> { template<typename _II, typename _OI> static _OI __copy_m(_II __first, _II __last, _OI __result) { typedef typename iterator_traits<_II>::difference_type _Distance; for(_Distance __n = __last - __first; __n > 0; --__n) { *__result = *__first; ++__first; ++__result; } return __result; } }; #if __cplusplus >= 201103L template<> struct __copy_move<true, false, random_access_iterator_tag> { template<typename _II, typename _OI> static _OI __copy_m(_II __first, _II __last, _OI __result) { typedef typename iterator_traits<_II>::difference_type _Distance; for(_Distance __n = __last - __first; __n > 0; --__n) { *__result = std::move(*__first); ++__first; ++__result; } return __result; } }; #endif template<bool _IsMove> struct __copy_move<_IsMove, true, random_access_iterator_tag> { template<typename _Tp> static _Tp* __copy_m(const _Tp* __first, const _Tp* __last, _Tp* __result) { #if __cplusplus >= 201103L // trivial types can have deleted assignment static_assert( is_copy_assignable<_Tp>::value, "type is not assignable" ); #endif const ptrdiff_t _Num = __last - __first; if (_Num) __builtin_memmove(__result, __first, sizeof(_Tp) * _Num); return __result + _Num; } }; template<bool _IsMove, typename _II, typename _OI> inline _OI __copy_move_a(_II __first, _II __last, _OI __result) { typedef typename iterator_traits<_II>::value_type _ValueTypeI; typedef typename iterator_traits<_OI>::value_type _ValueTypeO; typedef typename iterator_traits<_II>::iterator_category _Category; const bool __simple = (__is_trivial(_ValueTypeI) && __is_pointer<_II>::__value && __is_pointer<_OI>::__value && __are_same<_ValueTypeI, _ValueTypeO>::__value); return std::__copy_move<_IsMove, __simple, _Category>::__copy_m(__first, __last, __result); } // Helpers for streambuf iterators (either istream or ostream). // NB: avoid including <iosfwd>, relatively large. template<typename _CharT> struct char_traits; template<typename _CharT, typename _Traits> class istreambuf_iterator; template<typename _CharT, typename _Traits> class ostreambuf_iterator; template<bool _IsMove, typename _CharT> typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value, ostreambuf_iterator<_CharT, char_traits<_CharT> > >::__type __copy_move_a2(_CharT*, _CharT*, ostreambuf_iterator<_CharT, char_traits<_CharT> >); template<bool _IsMove, typename _CharT> typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value, ostreambuf_iterator<_CharT, char_traits<_CharT> > >::__type __copy_move_a2(const _CharT*, const _CharT*, ostreambuf_iterator<_CharT, char_traits<_CharT> >); template<bool _IsMove, typename _CharT> typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value, _CharT*>::__type __copy_move_a2(istreambuf_iterator<_CharT, char_traits<_CharT> >, istreambuf_iterator<_CharT, char_traits<_CharT> >, _CharT*); template<bool _IsMove, typename _II, typename _OI> inline _OI __copy_move_a2(_II __first, _II __last, _OI __result) { return _OI(std::__copy_move_a<_IsMove>(std::__niter_base(__first), std::__niter_base(__last), std::__niter_base(__result))); } /** * @brief Copies the range [first,last) into result. * @ingroup mutating_algorithms * @param __first An input iterator. * @param __last An input iterator. * @param __result An output iterator. * @return result + (first - last) * * This inline function will boil down to a call to @c memmove whenever * possible. Failing that, if random access iterators are passed, then the * loop count will be known (and therefore a candidate for compiler * optimizations such as unrolling). Result may not be contained within * [first,last); the copy_backward function should be used instead. * * Note that the end of the output range is permitted to be contained * within [first,last). */ template<typename _II, typename _OI> inline _OI copy(_II __first, _II __last, _OI __result) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_II>) __glibcxx_function_requires(_OutputIteratorConcept<_OI, typename iterator_traits<_II>::value_type>) __glibcxx_requires_valid_range(__first, __last); return (std::__copy_move_a2<__is_move_iterator<_II>::__value> (std::__miter_base(__first), std::__miter_base(__last), __result)); } #if __cplusplus >= 201103L /** * @brief Moves the range [first,last) into result. * @ingroup mutating_algorithms * @param __first An input iterator. * @param __last An input iterator. * @param __result An output iterator. * @return result + (first - last) * * This inline function will boil down to a call to @c memmove whenever * possible. Failing that, if random access iterators are passed, then the * loop count will be known (and therefore a candidate for compiler * optimizations such as unrolling). Result may not be contained within * [first,last); the move_backward function should be used instead. * * Note that the end of the output range is permitted to be contained * within [first,last). */ template<typename _II, typename _OI> inline _OI move(_II __first, _II __last, _OI __result) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_II>) __glibcxx_function_requires(_OutputIteratorConcept<_OI, typename iterator_traits<_II>::value_type>) __glibcxx_requires_valid_range(__first, __last); return std::__copy_move_a2<true>(std::__miter_base(__first), std::__miter_base(__last), __result); } #define _GLIBCXX_MOVE3(_Tp, _Up, _Vp) std::move(_Tp, _Up, _Vp) #else #define _GLIBCXX_MOVE3(_Tp, _Up, _Vp) std::copy(_Tp, _Up, _Vp) #endif template<bool, bool, typename> struct __copy_move_backward { template<typename _BI1, typename _BI2> static _BI2 __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result) { while (__first != __last) *--__result = *--__last; return __result; } }; #if __cplusplus >= 201103L template<typename _Category> struct __copy_move_backward<true, false, _Category> { template<typename _BI1, typename _BI2> static _BI2 __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result) { while (__first != __last) *--__result = std::move(*--__last); return __result; } }; #endif template<> struct __copy_move_backward<false, false, random_access_iterator_tag> { template<typename _BI1, typename _BI2> static _BI2 __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result) { typename iterator_traits<_BI1>::difference_type __n; for (__n = __last - __first; __n > 0; --__n) *--__result = *--__last; return __result; } }; #if __cplusplus >= 201103L template<> struct __copy_move_backward<true, false, random_access_iterator_tag> { template<typename _BI1, typename _BI2> static _BI2 __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result) { typename iterator_traits<_BI1>::difference_type __n; for (__n = __last - __first; __n > 0; --__n) *--__result = std::move(*--__last); return __result; } }; #endif template<bool _IsMove> struct __copy_move_backward<_IsMove, true, random_access_iterator_tag> { template<typename _Tp> static _Tp* __copy_move_b(const _Tp* __first, const _Tp* __last, _Tp* __result) { #if __cplusplus >= 201103L // trivial types can have deleted assignment static_assert( is_copy_assignable<_Tp>::value, "type is not assignable" ); #endif const ptrdiff_t _Num = __last - __first; if (_Num) __builtin_memmove(__result - _Num, __first, sizeof(_Tp) * _Num); return __result - _Num; } }; template<bool _IsMove, typename _BI1, typename _BI2> inline _BI2 __copy_move_backward_a(_BI1 __first, _BI1 __last, _BI2 __result) { typedef typename iterator_traits<_BI1>::value_type _ValueType1; typedef typename iterator_traits<_BI2>::value_type _ValueType2; typedef typename iterator_traits<_BI1>::iterator_category _Category; const bool __simple = (__is_trivial(_ValueType1) && __is_pointer<_BI1>::__value && __is_pointer<_BI2>::__value && __are_same<_ValueType1, _ValueType2>::__value); return std::__copy_move_backward<_IsMove, __simple, _Category>::__copy_move_b(__first, __last, __result); } template<bool _IsMove, typename _BI1, typename _BI2> inline _BI2 __copy_move_backward_a2(_BI1 __first, _BI1 __last, _BI2 __result) { return _BI2(std::__copy_move_backward_a<_IsMove> (std::__niter_base(__first), std::__niter_base(__last), std::__niter_base(__result))); } /** * @brief Copies the range [first,last) into result. * @ingroup mutating_algorithms * @param __first A bidirectional iterator. * @param __last A bidirectional iterator. * @param __result A bidirectional iterator. * @return result - (first - last) * * The function has the same effect as copy, but starts at the end of the * range and works its way to the start, returning the start of the result. * This inline function will boil down to a call to @c memmove whenever * possible. Failing that, if random access iterators are passed, then the * loop count will be known (and therefore a candidate for compiler * optimizations such as unrolling). * * Result may not be in the range (first,last]. Use copy instead. Note * that the start of the output range may overlap [first,last). */ template<typename _BI1, typename _BI2> inline _BI2 copy_backward(_BI1 __first, _BI1 __last, _BI2 __result) { // concept requirements __glibcxx_function_requires(_BidirectionalIteratorConcept<_BI1>) __glibcxx_function_requires(_Mutable_BidirectionalIteratorConcept<_BI2>) __glibcxx_function_requires(_ConvertibleConcept< typename iterator_traits<_BI1>::value_type, typename iterator_traits<_BI2>::value_type>) __glibcxx_requires_valid_range(__first, __last); return (std::__copy_move_backward_a2<__is_move_iterator<_BI1>::__value> (std::__miter_base(__first), std::__miter_base(__last), __result)); } #if __cplusplus >= 201103L /** * @brief Moves the range [first,last) into result. * @ingroup mutating_algorithms * @param __first A bidirectional iterator. * @param __last A bidirectional iterator. * @param __result A bidirectional iterator. * @return result - (first - last) * * The function has the same effect as move, but starts at the end of the * range and works its way to the start, returning the start of the result. * This inline function will boil down to a call to @c memmove whenever * possible. Failing that, if random access iterators are passed, then the * loop count will be known (and therefore a candidate for compiler * optimizations such as unrolling). * * Result may not be in the range (first,last]. Use move instead. Note * that the start of the output range may overlap [first,last). */ template<typename _BI1, typename _BI2> inline _BI2 move_backward(_BI1 __first, _BI1 __last, _BI2 __result) { // concept requirements __glibcxx_function_requires(_BidirectionalIteratorConcept<_BI1>) __glibcxx_function_requires(_Mutable_BidirectionalIteratorConcept<_BI2>) __glibcxx_function_requires(_ConvertibleConcept< typename iterator_traits<_BI1>::value_type, typename iterator_traits<_BI2>::value_type>) __glibcxx_requires_valid_range(__first, __last); return std::__copy_move_backward_a2<true>(std::__miter_base(__first), std::__miter_base(__last), __result); } #define _GLIBCXX_MOVE_BACKWARD3(_Tp, _Up, _Vp) std::move_backward(_Tp, _Up, _Vp) #else #define _GLIBCXX_MOVE_BACKWARD3(_Tp, _Up, _Vp) std::copy_backward(_Tp, _Up, _Vp) #endif template<typename _ForwardIterator, typename _Tp> inline typename __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type __fill_a(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { for (; __first != __last; ++__first) *__first = __value; } template<typename _ForwardIterator, typename _Tp> inline typename __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type __fill_a(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { const _Tp __tmp = __value; for (; __first != __last; ++__first) *__first = __tmp; } // Specialization: for char types we can use memset. template<typename _Tp> inline typename __gnu_cxx::__enable_if<__is_byte<_Tp>::__value, void>::__type __fill_a(_Tp* __first, _Tp* __last, const _Tp& __c) { const _Tp __tmp = __c; __builtin_memset(__first, static_cast<unsigned char>(__tmp), __last - __first); } /** * @brief Fills the range [first,last) with copies of value. * @ingroup mutating_algorithms * @param __first A forward iterator. * @param __last A forward iterator. * @param __value A reference-to-const of arbitrary type. * @return Nothing. * * This function fills a range with copies of the same value. For char * types filling contiguous areas of memory, this becomes an inline call * to @c memset or @c wmemset. */ template<typename _ForwardIterator, typename _Tp> inline void fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { // concept requirements __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< _ForwardIterator>) __glibcxx_requires_valid_range(__first, __last); std::__fill_a(std::__niter_base(__first), std::__niter_base(__last), __value); } template<typename _OutputIterator, typename _Size, typename _Tp> inline typename __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value) { for (__decltype(__n + 0) __niter = __n; __niter > 0; --__niter, ++__first) *__first = __value; return __first; } template<typename _OutputIterator, typename _Size, typename _Tp> inline typename __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value) { const _Tp __tmp = __value; for (__decltype(__n + 0) __niter = __n; __niter > 0; --__niter, ++__first) *__first = __tmp; return __first; } template<typename _Size, typename _Tp> inline typename __gnu_cxx::__enable_if<__is_byte<_Tp>::__value, _Tp*>::__type __fill_n_a(_Tp* __first, _Size __n, const _Tp& __c) { std::__fill_a(__first, __first + __n, __c); return __first + __n; } /** * @brief Fills the range [first,first+n) with copies of value. * @ingroup mutating_algorithms * @param __first An output iterator. * @param __n The count of copies to perform. * @param __value A reference-to-const of arbitrary type. * @return The iterator at first+n. * * This function fills a range with copies of the same value. For char * types filling contiguous areas of memory, this becomes an inline call * to @c memset or @ wmemset. * * _GLIBCXX_RESOLVE_LIB_DEFECTS * DR 865. More algorithms that throw away information */ template<typename _OI, typename _Size, typename _Tp> inline _OI fill_n(_OI __first, _Size __n, const _Tp& __value) { // concept requirements __glibcxx_function_requires(_OutputIteratorConcept<_OI, _Tp>) return _OI(std::__fill_n_a(std::__niter_base(__first), __n, __value)); } template<bool _BoolType> struct __equal { template<typename _II1, typename _II2> static bool equal(_II1 __first1, _II1 __last1, _II2 __first2) { for (; __first1 != __last1; ++__first1, ++__first2) if (!(*__first1 == *__first2)) return false; return true; } }; template<> struct __equal<true> { template<typename _Tp> static bool equal(const _Tp* __first1, const _Tp* __last1, const _Tp* __first2) { return !__builtin_memcmp(__first1, __first2, sizeof(_Tp) * (__last1 - __first1)); } }; template<typename _II1, typename _II2> inline bool __equal_aux(_II1 __first1, _II1 __last1, _II2 __first2) { typedef typename iterator_traits<_II1>::value_type _ValueType1; typedef typename iterator_traits<_II2>::value_type _ValueType2; const bool __simple = ((__is_integer<_ValueType1>::__value || __is_pointer<_ValueType1>::__value) && __is_pointer<_II1>::__value && __is_pointer<_II2>::__value && __are_same<_ValueType1, _ValueType2>::__value); return std::__equal<__simple>::equal(__first1, __last1, __first2); } template<typename, typename> struct __lc_rai { template<typename _II1, typename _II2> static _II1 __newlast1(_II1, _II1 __last1, _II2, _II2) { return __last1; } template<typename _II> static bool __cnd2(_II __first, _II __last) { return __first != __last; } }; template<> struct __lc_rai<random_access_iterator_tag, random_access_iterator_tag> { template<typename _RAI1, typename _RAI2> static _RAI1 __newlast1(_RAI1 __first1, _RAI1 __last1, _RAI2 __first2, _RAI2 __last2) { const typename iterator_traits<_RAI1>::difference_type __diff1 = __last1 - __first1; const typename iterator_traits<_RAI2>::difference_type __diff2 = __last2 - __first2; return __diff2 < __diff1 ? __first1 + __diff2 : __last1; } template<typename _RAI> static bool __cnd2(_RAI, _RAI) { return true; } }; template<typename _II1, typename _II2, typename _Compare> bool __lexicographical_compare_impl(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2, _Compare __comp) { typedef typename iterator_traits<_II1>::iterator_category _Category1; typedef typename iterator_traits<_II2>::iterator_category _Category2; typedef std::__lc_rai<_Category1, _Category2> __rai_type; __last1 = __rai_type::__newlast1(__first1, __last1, __first2, __last2); for (; __first1 != __last1 && __rai_type::__cnd2(__first2, __last2); ++__first1, ++__first2) { if (__comp(__first1, __first2)) return true; if (__comp(__first2, __first1)) return false; } return __first1 == __last1 && __first2 != __last2; } template<bool _BoolType> struct __lexicographical_compare { template<typename _II1, typename _II2> static bool __lc(_II1, _II1, _II2, _II2); }; template<bool _BoolType> template<typename _II1, typename _II2> bool __lexicographical_compare<_BoolType>:: __lc(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2) { return std::__lexicographical_compare_impl(__first1, __last1, __first2, __last2, __gnu_cxx::__ops::__iter_less_iter()); } template<> struct __lexicographical_compare<true> { template<typename _Tp, typename _Up> static bool __lc(const _Tp* __first1, const _Tp* __last1, const _Up* __first2, const _Up* __last2) { const size_t __len1 = __last1 - __first1; const size_t __len2 = __last2 - __first2; const int __result = __builtin_memcmp(__first1, __first2, std::min(__len1, __len2)); return __result != 0 ? __result < 0 : __len1 < __len2; } }; template<typename _II1, typename _II2> inline bool __lexicographical_compare_aux(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2) { typedef typename iterator_traits<_II1>::value_type _ValueType1; typedef typename iterator_traits<_II2>::value_type _ValueType2; const bool __simple = (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed && __is_pointer<_II1>::__value && __is_pointer<_II2>::__value); return std::__lexicographical_compare<__simple>::__lc(__first1, __last1, __first2, __last2); } template<typename _ForwardIterator, typename _Tp, typename _Compare> _ForwardIterator __lower_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __val, _Compare __comp) { typedef typename iterator_traits<_ForwardIterator>::difference_type _DistanceType; _DistanceType __len = std::distance(__first, __last); while (__len > 0) { _DistanceType __half = __len >> 1; _ForwardIterator __middle = __first; std::advance(__middle, __half); if (__comp(__middle, __val)) { __first = __middle; ++__first; __len = __len - __half - 1; } else __len = __half; } return __first; } /** * @brief Finds the first position in which @a val could be inserted * without changing the ordering. * @param __first An iterator. * @param __last Another iterator. * @param __val The search term. * @return An iterator pointing to the first element <em>not less * than</em> @a val, or end() if every element is less than * @a val. * @ingroup binary_search_algorithms */ template<typename _ForwardIterator, typename _Tp> inline _ForwardIterator lower_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __val) { // concept requirements __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) __glibcxx_function_requires(_LessThanOpConcept< typename iterator_traits<_ForwardIterator>::value_type, _Tp>) __glibcxx_requires_partitioned_lower(__first, __last, __val); return std::__lower_bound(__first, __last, __val, __gnu_cxx::__ops::__iter_less_val()); } /// This is a helper function for the sort routines and for random.tcc. // Precondition: __n > 0. inline _GLIBCXX_CONSTEXPR int __lg(int __n) { return sizeof(int) * __CHAR_BIT__ - 1 - __builtin_clz(__n); } inline _GLIBCXX_CONSTEXPR unsigned __lg(unsigned __n) { return sizeof(int) * __CHAR_BIT__ - 1 - __builtin_clz(__n); } inline _GLIBCXX_CONSTEXPR long __lg(long __n) { return sizeof(long) * __CHAR_BIT__ - 1 - __builtin_clzl(__n); } inline _GLIBCXX_CONSTEXPR unsigned long __lg(unsigned long __n) { return sizeof(long) * __CHAR_BIT__ - 1 - __builtin_clzl(__n); } inline _GLIBCXX_CONSTEXPR long long __lg(long long __n) { return sizeof(long long) * __CHAR_BIT__ - 1 - __builtin_clzll(__n); } inline _GLIBCXX_CONSTEXPR unsigned long long __lg(unsigned long long __n) { return sizeof(long long) * __CHAR_BIT__ - 1 - __builtin_clzll(__n); } _GLIBCXX_END_NAMESPACE_VERSION _GLIBCXX_BEGIN_NAMESPACE_ALGO /** * @brief Tests a range for element-wise equality. * @ingroup non_mutating_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @return A boolean true or false. * * This compares the elements of two ranges using @c == and returns true or * false depending on whether all of the corresponding elements of the * ranges are equal. */ template<typename _II1, typename _II2> inline bool equal(_II1 __first1, _II1 __last1, _II2 __first2) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_II1>) __glibcxx_function_requires(_InputIteratorConcept<_II2>) __glibcxx_function_requires(_EqualOpConcept< typename iterator_traits<_II1>::value_type, typename iterator_traits<_II2>::value_type>) __glibcxx_requires_valid_range(__first1, __last1); return std::__equal_aux(std::__niter_base(__first1), std::__niter_base(__last1), std::__niter_base(__first2)); } /** * @brief Tests a range for element-wise equality. * @ingroup non_mutating_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @param __binary_pred A binary predicate @link functors * functor@endlink. * @return A boolean true or false. * * This compares the elements of two ranges using the binary_pred * parameter, and returns true or * false depending on whether all of the corresponding elements of the * ranges are equal. */ template<typename _IIter1, typename _IIter2, typename _BinaryPredicate> inline bool equal(_IIter1 __first1, _IIter1 __last1, _IIter2 __first2, _BinaryPredicate __binary_pred) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_IIter1>) __glibcxx_function_requires(_InputIteratorConcept<_IIter2>) __glibcxx_requires_valid_range(__first1, __last1); for (; __first1 != __last1; ++__first1, ++__first2) if (!bool(__binary_pred(*__first1, *__first2))) return false; return true; } #if __cplusplus > 201103L #define __cpp_lib_robust_nonmodifying_seq_ops 201304 /** * @brief Tests a range for element-wise equality. * @ingroup non_mutating_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @param __last2 An input iterator. * @return A boolean true or false. * * This compares the elements of two ranges using @c == and returns true or * false depending on whether all of the corresponding elements of the * ranges are equal. */ template<typename _II1, typename _II2> inline bool equal(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_II1>) __glibcxx_function_requires(_InputIteratorConcept<_II2>) __glibcxx_function_requires(_EqualOpConcept< typename iterator_traits<_II1>::value_type, typename iterator_traits<_II2>::value_type>) __glibcxx_requires_valid_range(__first1, __last1); __glibcxx_requires_valid_range(__first2, __last2); using _RATag = random_access_iterator_tag; using _Cat1 = typename iterator_traits<_II1>::iterator_category; using _Cat2 = typename iterator_traits<_II2>::iterator_category; using _RAIters = __and_<is_same<_Cat1, _RATag>, is_same<_Cat2, _RATag>>; if (_RAIters()) { auto __d1 = std::distance(__first1, __last1); auto __d2 = std::distance(__first2, __last2); if (__d1 != __d2) return false; return _GLIBCXX_STD_A::equal(__first1, __last1, __first2); } for (; __first1 != __last1 && __first2 != __last2; ++__first1, ++__first2) if (!(*__first1 == *__first2)) return false; return __first1 == __last1 && __first2 == __last2; } /** * @brief Tests a range for element-wise equality. * @ingroup non_mutating_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @param __last2 An input iterator. * @param __binary_pred A binary predicate @link functors * functor@endlink. * @return A boolean true or false. * * This compares the elements of two ranges using the binary_pred * parameter, and returns true or * false depending on whether all of the corresponding elements of the * ranges are equal. */ template<typename _IIter1, typename _IIter2, typename _BinaryPredicate> inline bool equal(_IIter1 __first1, _IIter1 __last1, _IIter2 __first2, _IIter2 __last2, _BinaryPredicate __binary_pred) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_IIter1>) __glibcxx_function_requires(_InputIteratorConcept<_IIter2>) __glibcxx_requires_valid_range(__first1, __last1); __glibcxx_requires_valid_range(__first2, __last2); using _RATag = random_access_iterator_tag; using _Cat1 = typename iterator_traits<_IIter1>::iterator_category; using _Cat2 = typename iterator_traits<_IIter2>::iterator_category; using _RAIters = __and_<is_same<_Cat1, _RATag>, is_same<_Cat2, _RATag>>; if (_RAIters()) { auto __d1 = std::distance(__first1, __last1); auto __d2 = std::distance(__first2, __last2); if (__d1 != __d2) return false; return _GLIBCXX_STD_A::equal(__first1, __last1, __first2, __binary_pred); } for (; __first1 != __last1 && __first2 != __last2; ++__first1, ++__first2) if (!bool(__binary_pred(*__first1, *__first2))) return false; return __first1 == __last1 && __first2 == __last2; } #endif /** * @brief Performs @b dictionary comparison on ranges. * @ingroup sorting_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @param __last2 An input iterator. * @return A boolean true or false. * * <em>Returns true if the sequence of elements defined by the range * [first1,last1) is lexicographically less than the sequence of elements * defined by the range [first2,last2). Returns false otherwise.</em> * (Quoted from [25.3.8]/1.) If the iterators are all character pointers, * then this is an inline call to @c memcmp. */ template<typename _II1, typename _II2> inline bool lexicographical_compare(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2) { #ifdef _GLIBCXX_CONCEPT_CHECKS // concept requirements typedef typename iterator_traits<_II1>::value_type _ValueType1; typedef typename iterator_traits<_II2>::value_type _ValueType2; #endif __glibcxx_function_requires(_InputIteratorConcept<_II1>) __glibcxx_function_requires(_InputIteratorConcept<_II2>) __glibcxx_function_requires(_LessThanOpConcept<_ValueType1, _ValueType2>) __glibcxx_function_requires(_LessThanOpConcept<_ValueType2, _ValueType1>) __glibcxx_requires_valid_range(__first1, __last1); __glibcxx_requires_valid_range(__first2, __last2); return std::__lexicographical_compare_aux(std::__niter_base(__first1), std::__niter_base(__last1), std::__niter_base(__first2), std::__niter_base(__last2)); } /** * @brief Performs @b dictionary comparison on ranges. * @ingroup sorting_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @param __last2 An input iterator. * @param __comp A @link comparison_functors comparison functor@endlink. * @return A boolean true or false. * * The same as the four-parameter @c lexicographical_compare, but uses the * comp parameter instead of @c <. */ template<typename _II1, typename _II2, typename _Compare> inline bool lexicographical_compare(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2, _Compare __comp) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_II1>) __glibcxx_function_requires(_InputIteratorConcept<_II2>) __glibcxx_requires_valid_range(__first1, __last1); __glibcxx_requires_valid_range(__first2, __last2); return std::__lexicographical_compare_impl (__first1, __last1, __first2, __last2, __gnu_cxx::__ops::__iter_comp_iter(__comp)); } template<typename _InputIterator1, typename _InputIterator2, typename _BinaryPredicate> pair<_InputIterator1, _InputIterator2> __mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate __binary_pred) { while (__first1 != __last1 && __binary_pred(__first1, __first2)) { ++__first1; ++__first2; } return pair<_InputIterator1, _InputIterator2>(__first1, __first2); } /** * @brief Finds the places in ranges which don't match. * @ingroup non_mutating_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @return A pair of iterators pointing to the first mismatch. * * This compares the elements of two ranges using @c == and returns a pair * of iterators. The first iterator points into the first range, the * second iterator points into the second range, and the elements pointed * to by the iterators are not equal. */ template<typename _InputIterator1, typename _InputIterator2> inline pair<_InputIterator1, _InputIterator2> mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) __glibcxx_function_requires(_EqualOpConcept< typename iterator_traits<_InputIterator1>::value_type, typename iterator_traits<_InputIterator2>::value_type>) __glibcxx_requires_valid_range(__first1, __last1); return _GLIBCXX_STD_A::__mismatch(__first1, __last1, __first2, __gnu_cxx::__ops::__iter_equal_to_iter()); } /** * @brief Finds the places in ranges which don't match. * @ingroup non_mutating_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @param __binary_pred A binary predicate @link functors * functor@endlink. * @return A pair of iterators pointing to the first mismatch. * * This compares the elements of two ranges using the binary_pred * parameter, and returns a pair * of iterators. The first iterator points into the first range, the * second iterator points into the second range, and the elements pointed * to by the iterators are not equal. */ template<typename _InputIterator1, typename _InputIterator2, typename _BinaryPredicate> inline pair<_InputIterator1, _InputIterator2> mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate __binary_pred) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) __glibcxx_requires_valid_range(__first1, __last1); return _GLIBCXX_STD_A::__mismatch(__first1, __last1, __first2, __gnu_cxx::__ops::__iter_comp_iter(__binary_pred)); } #if __cplusplus > 201103L template<typename _InputIterator1, typename _InputIterator2, typename _BinaryPredicate> pair<_InputIterator1, _InputIterator2> __mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _BinaryPredicate __binary_pred) { while (__first1 != __last1 && __first2 != __last2 && __binary_pred(__first1, __first2)) { ++__first1; ++__first2; } return pair<_InputIterator1, _InputIterator2>(__first1, __first2); } /** * @brief Finds the places in ranges which don't match. * @ingroup non_mutating_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @param __last2 An input iterator. * @return A pair of iterators pointing to the first mismatch. * * This compares the elements of two ranges using @c == and returns a pair * of iterators. The first iterator points into the first range, the * second iterator points into the second range, and the elements pointed * to by the iterators are not equal. */ template<typename _InputIterator1, typename _InputIterator2> inline pair<_InputIterator1, _InputIterator2> mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) __glibcxx_function_requires(_EqualOpConcept< typename iterator_traits<_InputIterator1>::value_type, typename iterator_traits<_InputIterator2>::value_type>) __glibcxx_requires_valid_range(__first1, __last1); __glibcxx_requires_valid_range(__first2, __last2); return _GLIBCXX_STD_A::__mismatch(__first1, __last1, __first2, __last2, __gnu_cxx::__ops::__iter_equal_to_iter()); } /** * @brief Finds the places in ranges which don't match. * @ingroup non_mutating_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @param __last2 An input iterator. * @param __binary_pred A binary predicate @link functors * functor@endlink. * @return A pair of iterators pointing to the first mismatch. * * This compares the elements of two ranges using the binary_pred * parameter, and returns a pair * of iterators. The first iterator points into the first range, the * second iterator points into the second range, and the elements pointed * to by the iterators are not equal. */ template<typename _InputIterator1, typename _InputIterator2, typename _BinaryPredicate> inline pair<_InputIterator1, _InputIterator2> mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _BinaryPredicate __binary_pred) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) __glibcxx_requires_valid_range(__first1, __last1); __glibcxx_requires_valid_range(__first2, __last2); return _GLIBCXX_STD_A::__mismatch(__first1, __last1, __first2, __last2, __gnu_cxx::__ops::__iter_comp_iter(__binary_pred)); } #endif _GLIBCXX_END_NAMESPACE_ALGO } // namespace std // NB: This file is included within many other C++ includes, as a way // of getting the base algorithms. So, make sure that parallel bits // come in too if requested. #ifdef _GLIBCXX_PARALLEL # include <parallel/algobase.h> #endif #endif
最新发布
12-20
### 解决 Unity 构建时依赖解析问题 当遇到 `unity could not resolve all files for configuration ':launcher:releaseRuntimeClasspath'` 错误时,这通常意味着构建过程中存在某些文件或库无法被正确识别或加载的情况。以下是几种可能的原因及解决方案: #### 1. 检查项目结构和配置 确保项目的目录结构符合预期标准。如果使用的是特定版本控制工具(如 SVN),需要注意忽略模式的应用仅限于已版本化的目录[^2]。 #### 2. 手动创建必要文件夹和文件 有时手动创建缺失的文件夹和初始化必要的配置文件可以解决问题。例如,在某些情况下,通过手工建立 `UnityAssemblies` 文件夹并在此文件夹内放置名为 `version.txt` 的空白文本文件能够使编译顺利进行[^1]。 #### 3. 更新渲染管线设置 对于涉及图形渲染路径更改的操作,比如切换到延迟着色(Deferred Shading)方式,则需确认这些改动已被适当集成至工程之中。新的表面着色器应当支持所选的渲染路径,并且可以在图形设置界面中调整相应的覆盖选项[^3]。 #### 4. 利用命令缓冲区扩展渲染管道 为了增强灵活性以及更好地管理资源加载顺序,可以通过脚本编写自定义命令缓冲区来优化渲染流程。利用此功能可以从不同阶段插入额外指令,从而改善整体性能表现[^4]。 ```csharp using UnityEngine; using UnityEngine.Rendering; public class CustomRenderPipeline : MonoBehaviour { void Start() { CommandBuffer buffer = new CommandBuffer(); buffer.name = "Custom Buffer"; // 添加绘制网格或其他操作 Camera.main.AddCommandBuffer(CameraEvent.AfterForwardOpaque, buffer); } } ``` 以上方法可以帮助排查并修复因依赖关系未成功解析而导致的构建失败问题。具体实施时应根据实际开发环境和个人需求灵活运用上述建议。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值