Class file editing method and apparatus, device, and medium
By initializing the bytecode processing framework during the Android application build process, registering multiple types of processors, and performing scanning and transformation in stages, the problem of repeated reading and writing of class files is solved, achieving efficient global cross-class analysis and multi-task collaboration, thus improving build performance and stability.
Patent Information
- Authority / Receiving Office
- CN · China
- Patent Type
- Applications(China)
- Current Assignee / Owner
- GUANGZHOU OVERSEAS KANGBAZI NETWORK TECHNOLOGY CO LTD
- Filing Date
- 2026-03-30
- Publication Date
- 2026-06-19
AI Technical Summary
Existing technologies in Android application building processes suffer from disk I/O overhead and CPU resource waste caused by repeated reading and writing of class files. They also fail to achieve stability in global cross-class analysis and multi-task collaboration, and lack a unified collaboration and sequence control mechanism.
By initializing the bytecode processing framework, various types of bytecode processors are registered in a pre-arranged order, including general task processors, instrumentation processors, and traversal processors. The scanning and transformation phases are executed in stages to obtain global class information and perform bytecode modification operations in sequence.
It significantly improves build performance, avoids repeated bytecode reading and writing, realizes cross-class association modification of global context and orderly multi-processor collaborative work, and ensures the stability of multi-task collaboration.
Smart Images

Figure CN122240124A_ABST
Abstract
Description
Technical Field
[0001] This application relates to the field of code compilation technology, and in particular to a file editing method, apparatus, device, and medium thereof. Background Technology
[0002] In the Android application building process, class file editing technology is often used to implement key functions such as performance monitoring, security hardening, and code analysis. Existing class file editing solutions typically rely on standard interfaces provided by build tools or are implemented by registering a separate Gradle plugin.
[0003] However, as the scale of applications expands and functional requirements become more complex, existing technical solutions have gradually revealed the following shortcomings: First, different instrumentation requirements are typically achieved by registering separate build tasks or plugins. Due to the lack of a unified management framework, each independent task must execute its own complete bytecode reading, parsing, processing, and writing process. This fragmented approach leads to the repeated reading and writing of the same type of files in the build pipeline, resulting in significant redundant disk I / O overhead and wasted CPU resources, severely slowing down the overall build speed.
[0004] Secondly, existing bytecode processing interfaces (such as the AGP Transform API or Instrumentation API) typically employ a single-stage streaming processing model, meaning that after reading a class file, modifications must be performed immediately and the result output. This model results in a lack of global perspective during processing, making it impossible to obtain complete class inheritance relationships or method call graphs before modification. This limits the implementation of complex instrumentation scenarios such as cross-class dependency analysis and full dead code detection.
[0005] Furthermore, when multiple processing units (such as event tracking plugins, privacy compliance plugins, and time-consuming monitoring plugins) need to modify the same bytecode file, existing technologies lack a unified coordination and sequence control mechanism. The execution order of each processing unit often depends on the default scheduling strategy of the build tool or the application order of plugins, making it difficult for developers to perform precise pre-arrangement. This disordered execution environment can easily lead to bytecode modification conflicts, or cause inconsistencies in the final output due to the randomness of the processing order, making it difficult to guarantee the determinism of the build result.
[0006] In summary, existing technologies cannot guarantee build performance while simultaneously addressing complex global cross-class analysis requirements and the stability of multi-task collaboration. There is an urgent need for a class file editing solution that can unify the orchestration of heterogeneous processing modes, support global context analysis, and control the execution order. Summary of the Invention
[0007] The purpose of this application is to solve the above-mentioned problems by providing a method, apparatus, device, and medium for editing a type of document.
[0008] According to one aspect of this application, a method for editing a type of document is provided, comprising the following steps: In response to the build variant event, initialize the bytecode processing framework; In the bytecode processing framework, multiple types of bytecode processors are registered in a pre-arranged order, including general-purpose task processors, instrumentation processors, and traversal processors. The target class file set is obtained through the bytecode processing framework, and the various types of bytecode processors are invoked to perform the scanning and conversion phases on the target class file set sequentially. During the scanning phase, the bytecode of the target class file set is read, and the traversal processor is called to obtain the global class information of the bytecode; During the conversion phase, the class files to be modified in the target class file set are identified based on the global class information, and all registered bytecode processors are called in a pre-arranged order to perform bytecode modification operations on the bytecode of the class files to be modified in sequence, and the final class file is output.
[0009] According to another aspect of this application, a document editing device is provided, comprising: The framework initialization module is used to initialize the bytecode processing framework in response to build variant events; The processor registration module is used to register multiple types of bytecode processors in the bytecode processing framework in a pre-arranged order. The multiple types of bytecode processors include general task processors, instrumentation processors, and traversal processors. A two-stage scheduling module is used to obtain a set of target class files through the bytecode processing framework, and call the various types of bytecode processors to perform a scanning stage and a conversion stage on the set of target class files in sequence; The scanning execution module is used to read the bytecode of the target class file set during the scanning phase and obtain the global class information of the bytecode by traversing the processor. The conversion execution module is used to identify the class files to be modified in the target class file set according to the global class information during the conversion stage, and to call all registered bytecode processors in a pre-arranged order to perform bytecode modification operations on the bytecode of the class files to be modified in sequence, and output the final class file.
[0010] According to another aspect of this application, an electronic device is provided, including a central processing unit and a memory, wherein the central processing unit is configured to invoke and run a computer program stored in the memory to perform the steps of the file editing method described in this application.
[0011] According to another aspect of this application, a non-volatile readable storage medium is provided, which stores a computer program implemented according to the file editing method in the form of computer-readable instructions, wherein the computer program, when invoked by a computer, performs the steps included in the method.
[0012] Compared to existing technologies, this application initializes a bytecode processing framework and registers multiple types of bytecode processors in a pre-arranged order, uniformly scheduling the execution of the scanning and transformation phases on the target class file set. This avoids repeated bytecode reading and writing caused by independent tasks, significantly improving build performance. By obtaining global class information during the scanning phase and identifying the class file to be modified based on the global class information during the transformation phase, cross-class association modification based on the global context is achieved. By calling all registered bytecode processors in a pre-arranged order to execute bytecode modification operations sequentially, the orderly collaboration of multiple processors is ensured, guaranteeing the stability of multi-task collaboration. Attached Figure Description
[0013] Figure 1 This is a flowchart illustrating one embodiment of the file editing method of this application; Figure 2 This is a schematic block diagram of the file editing device of this application; Figure 3 This is a schematic diagram of the structure of an electronic device used in this application. Detailed Implementation
[0014] To facilitate understanding of the various embodiments of this application, exemplary software architectures and application scenarios will be introduced first.
[0015] The software architecture of this application aims to build a unified bytecode processing framework system. This software architecture can run on an Android build host, such as a CI server or a developer's local machine, and consists of three parts: the build trigger end, the framework core end, and the processor module end.
[0016] The build trigger can be configured to listen for Build VariantEvents in the Android build host, and when the event occurs, trigger the framework's initialization process locally.
[0017] The core of the framework can be configured as a scheduling hub running on the central processing unit. It is the logical execution body of the bytecode processing framework, responsible for responding to build variant events triggered by the build trigger and performing container management, registration management and process orchestration operations.
[0018] The processor module can be configured as various types of bytecode processor instances stored in memory, including general task processors, instrumentation processors, and traversal processors. As functional execution nodes, they are loaded by the framework core and registered in the bytecode processing framework, and execute specific bytecode scanning and modification logic under the scheduling of the framework core.
[0019] In an exemplary application scenario, the class file editing method of this application can be applied to the development and building process of Android applications based on Android build tools, such as Gradle's Android build tool. In this process, Android build tools typically need to integrate various functional plugins to meet complex business requirements, such as performance monitoring plugins (APM), security hardening plugins, and business tracking plugins. These functional plugins can be loaded and instantiated as specific bytecode processor instances within the processor module of the software architecture of this application, serving as concrete business implementation packages. These instances run uniformly on the same Android build host and are uniformly orchestrated and managed by the core framework of this application based on the bytecode processing framework throughout the lifecycle of the Android build tool.
[0020] Through the detailed description of the software architecture and application scenarios described above, a better understanding of the specific application of the class file editing method of this application in the field of code compilation technology can be achieved. The following will elaborate on the detailed description of various specific embodiments of this application based on these exemplary contents.
[0021] like Figure 1 As shown, in one embodiment, the class file editing method of this application includes: Step S5100: In response to the build variant event, initialize the bytecode processing framework.
[0022] The core of the framework listens in real time for build variant events generated by the Android build tools during the configuration phase through the build trigger. In response to the listen for build variant events, the framework instantiates the bytecode processing environment in memory according to the build variant configuration of the current Android application.
[0023] In the development and build process of Android applications, different output artifacts are usually generated based on the combination of build type and product flavor. Each specific combination (such as ProDebug) is a build variant.
[0024] The build trigger can be a class that implements the standard plugin interface for Android build tools, such as implementing Plugin. <project>The interface is loaded into the Android build tool's runtime environment. The build trigger can read the current Android application's properties, identify the application's specific type (e.g., Application, Library, or Dynamic Feature), and obtain the corresponding extended configuration object. The framework core can call the variant API provided by the Android build tool through the build trigger to register listener callback functions generated for variants, which are used to respond to build variant events.
[0025] When a build variant event is received, the framework core can parse the Domain-Specific Language (DSL) configuration block defined by the developer in the Android application's build script (e.g., build.gradle). The framework core can then map the on / off states, log levels, lists of processors to be enabled, and parameters of each processor defined in the build script into in-memory configuration objects for initializing the bytecode processing framework.
[0026] The core framework can build a multi-target log distribution system based on configuration objects. The construction process includes defining a standard log interface, such as ILogger, which specifies the output format of four log levels: DEBUG, INFO, WARN, and ERROR; instantiating a composite pattern dispatcher, such as LogDistributor, which is configured to forward each received log message to multiple specific log implementations simultaneously. These implementations include, but are not limited to, the Android build tool's system log Gradle Logger, the independent file log File Logger, and the cached log Cached Logger used for subsequent report generation; and using the decorator pattern to encapsulate a hierarchical filter for the log system, such as the LevelLog decorator. This filter dynamically intercepts and filters low-priority log entries at runtime based on the log levels set in the DSL configuration, ensuring the conciseness and effectiveness of log output.
[0027] Step S5200: Register multiple types of bytecode processors in the bytecode processing framework in a pre-arranged order. The multiple types of bytecode processors include general task processors, instrumentation processors, and traversal processors.
[0028] The framework core scans and identifies processor classes defined in the processor module that correspond to various types of bytecode processors. Based on the specific type of the identified processor class, it performs registration operations for general task processors, instrumentation processors, and traversal processors in a pre-arranged order. The framework core can also activate its internally integrated service discovery mechanism to scan metadata configuration files in Android applications and their dependent environments to automatically identify processor classes declared in the processor module.
[0029] Service discovery mechanisms can refer to a mechanism that automatically detects and loads components at runtime, allowing developers to declare processors in a standardized way without hard-coding references in the framework code, thus decoupling the framework from specific business logic.
[0030] The core framework leverages Java's service provisioning interface mechanism to automatically discover processor classes in the processor module. Specifically, processor classes in the processor module are configured with specific annotations (e.g., the `@AutoService` annotation). Based on these annotations, a metadata configuration file is generated in a specific resource path (e.g., the `META-INF / services / ` directory) within the Android application's build artifacts or dependent libraries. This metadata configuration file is named with the fully qualified name of the interface, and its content records the fully qualified name of the specific processor class implementing that interface. The core framework can then launch its internally integrated ServiceLoader to scan resource paths in the Android application and its dependent environments. By reading and parsing the metadata configuration file, the core framework can obtain a list of all available processor class names in the current environment, thus automatically identifying the processor module components.
[0031] The core framework can execute differentiated registration strategies based on the type characteristics of the identified processor classes. For instrumented processors, it can execute a lookup strategy that targets the acquisition of class definitions and register the acquired class definitions in the underlying interface of the Android build tools. For general task processors and traversal processors, it can instantiate processor classes and register the generated instance objects in the internal container of the bytecode processing framework.
[0032] The core of the framework can predefine an enumeration or constant array to specify the registration order of the three types of processors. Based on Java's ServiceLoader mechanism, and combined with the @AutoService annotation, it automatically discovers all processor classes.
[0033] Step S5300: Obtain the target class file set through the bytecode processing framework, and call the various types of bytecode processors to perform the scanning phase and conversion phase on the target class file set in sequence.
[0034] The core framework relies on the file input interface of the Android build tool to intercept and aggregate all bytecode resources to be processed generated by the current Android application, constructing a logical set of target class files. Secondly, the core framework implements a serial, phased scheduling strategy. First, a scanning phase is initiated, importing the data stream of the target class file set into bytecode processors with analysis capabilities to complete the collection of global information. After confirming the complete end of the scanning phase and locking the collection results, a conversion phase is initiated, importing the data stream of the target class file set back into all registered bytecode processors, and performing substantive modification operations based on the aforementioned collection results.
[0035] The target class file set can refer to the directory of .class files generated during the Android application build process by the upstream compiler, such as Javac or Kotlinc, or the collection of third-party libraries (.jar files) that the project depends on.
[0036] The core of the framework can first set the execution state to the scanning state to filter out bytecode processors with analysis capabilities.
[0037] The core of the framework can maintain a custom worker class internally. This worker class runs based on the thread pool executor and can be configured with the core number of threads and the maximum number of threads to balance resource consumption. For example, the core number of threads can be configured to be 2 and the maximum number of threads can be the number of CPU cores.
[0038] The core framework can encapsulate each JAR file and class directory in the target class file set into an independent scanning task and submit it to the thread pool for concurrent execution via the Worker.submit() method.
[0039] The core framework utilizes a countdown latch to monitor the completion status of all concurrent tasks and combines it with atomic references to achieve rapid error propagation. If any child thread encounters an exception, the main thread can immediately detect it and interrupt the construction process. During this process, the core framework only authorizes the bytecode processor to perform read and record operations; write or modification operations are strictly prohibited.
[0040] Once the first round of traversal is complete, the framework core can execute a synchronization barrier operation. During this operation, the framework core can store the global context generated during the scanning phase into the global shared memory of the bytecode processing framework.
[0041] The core framework can employ concurrent hash mapping on class node caches, for example, pre-allocating 400 capacity, and apply synchronization locks such as synchronized blocks or @Synchronized annotations on critical read and write code blocks.
[0042] After the synchronization barrier is passed, the core of the framework can switch the execution state to the transition state and start the second round of traversal tasks.
[0043] During the conversion phase, the core framework can also utilize worker classes to concurrently handle modifications to class files.
[0044] For the modified bytecode serialization operation, the core of the framework can execute concurrently in multiple threads, collect the serialized binary results into a thread-safe list, and finally write them to the output JAR file by a single thread to avoid file I / O contention.
[0045] For processing ordinary class files that are not JAR files, such as AppendTask, the core framework can use the WorkerExecutor concurrency model.
[0046] The core framework can call the official Android build tool's WorkerExecutor.noIsolation() API to group file operations by change type (add / modify / delete). Each group contains a certain number of files (e.g., 50-100 files) and executes them concurrently as a work unit, following the order of "delete first, then modify, wait, then add" to ensure data consistency during incremental compilation.
[0047] Step S5400: During the scanning phase, the bytecode of the target class file set is read, and the traversal processor is called to obtain the global class information of the bytecode.
[0048] After entering the scanning phase, the core framework initiates a traversal and reading process for the target class file set. During the traversal, the core framework constructs a logical processing chain containing traversal processors and drives the internal bytecode reading component to parse the class files, propagating the parsed bytecode unidirectionally along the processing chain. The core framework calls the registered traversal processors through the processing chain, enabling them to collect cross-file metadata from the propagated bytecode, thereby generating global class information.
[0049] A processing link can refer to a data transfer structure that connects multiple processors in series. Through this structure, bytecode data only needs to be read once and can flow through all processors in sequence, thereby maximizing I / O efficiency.
[0050] Step S5500: During the conversion phase, the class files to be modified in the target class file set are identified according to the global class information, and all registered bytecode processors are called in a pre-arranged order to perform bytecode modification operations on the bytecode of the class files to be modified in sequence, and the final class file is output.
[0051] The core framework uses global class information built during the scanning phase as a decision-making basis to filter the target class file set, thereby identifying the class files to be modified that require business logic processing. Next, the core framework constructs a modification execution chain containing all registered bytecode processors. During this construction process, the core framework follows the registration order of each processor during the initialization phase, sequentially connecting the modification logic of each processor to the modification execution chain to establish a defined execution priority. Subsequently, the core framework drives the bytecode of the class file to be modified to propagate along the modification execution chain, enabling each bytecode processor to execute specific modification instructions on the bytecode in the registration order and pass the superimposed modification results to the downstream processors. Finally, the core framework reserializes the bytecode data processed by the modification execution chain to generate the final class file output.
[0052] The framework core can traverse the collection of target class files. For each class file, the framework core combines global class information and calls the interception interface provided by each bytecode processor, such as `interceptTransform`. The processor determines whether modification is needed based on the passed class information. If any processor returns "needs processing", the framework core marks the file as a class file to be modified; otherwise, it directly performs the file copy operation, skipping the subsequent parsing process to save performance.
[0053] For each class file to be modified, the framework core can create a new modification execution chain, such as ClassVisitorChain.
[0054] The core of the framework can read the internally maintained list of registered processors, traverse the list, and call the conversion interface of each processor in sequence according to the list index order.
[0055] After all class files have been processed, the core framework can trigger the report generation logic, calling the singleton HTML report generator. This generator uses double-checked locking to ensure thread safety and aggregates cached logs, time consumption statistics, and exception information collected during the build process through a multi-target log distribution system.
[0056] The core framework can render cached logs, time consumption statistics, and exception information into HTML files and output them to the build artifact directory, such as app / build / xplugin / {VariantName} / index.html, so that developers can view detailed instrumentation results and performance data.
[0057] Based on any embodiment of the method in this application, the step of registering multiple types of bytecode processors in a pre-arranged order within the bytecode processing framework, including general-purpose task processors, instrumentation processors, and traversal processors, includes: Step S5210: Obtain the processor class through the service loading mechanism. The processor class corresponds to the bytecode processor.
[0058] The framework core initiates the internally integrated service loading mechanism to scan the runtime environment of Android applications and their dependent libraries. By parsing the pre-set metadata configuration files in the runtime environment, the framework core automatically identifies and locates all processor classes declared in the processor module. Subsequently, the framework core loads the identified processor classes into memory to obtain the class definition or class reference of the processor class, which serves as the basis for subsequent registration or instantiation.
[0059] The service loading mechanism can be a standard dynamic discovery pattern (SPI, Service Provider Interface), allowing the framework to define interfaces, with the specific implementations provided by external modules. Through this mechanism, the framework core does not need to hard-code specific handler class names in the code; instead, it dynamically discovers and loads them by reading configuration files, thus decoupling the framework from business logic.
[0060] A processor class can refer to the static code definition of a bytecode processor, such as .class bytecode data that has not yet been instantiated as a runtime object. Obtaining the processor class is a necessary prerequisite step for subsequently determining whether to "register the class only" or "instantiate an object" based on the type.
[0061] Processor classes in the processor module must adhere to specific declaration specifications. Developers can mark processor classes with specific annotations, such as the `@AutoService` annotation, when writing them. During the compilation of the Android application, the annotation processor can parse this markup and automatically generate a metadata configuration file in a specific resource path of the build artifact (e.g., the `META-INF / services / ` directory). The metadata configuration file file name can be the fully qualified name of the service interface, and the file content can contain a list of the fully qualified names of all concrete processor classes that implement that interface.
[0062] During the initialization phase of the bytecode processing framework, the framework core can instantiate a service loader, such as using the JDK standard java.util.ServiceLoader or a custom classpath scanner. The framework core can instruct this service loader to scan the classpath of the current Android application, looking for all metadata configuration files that exist in specific resource paths of the build artifacts.
[0063] The core of the framework can read the metadata configuration file, parse the class name strings recorded in it line by line, call the current class loader, load the corresponding binary bytecode according to the parsed class name, generate the corresponding processor class object in the method area of the Java Virtual Machine, and collect all the obtained processor class objects into a temporary list or collection for subsequent type judgment and differential processing.
[0064] The framework core supports incremental loading optimization when retrieving processor classes. The core can calculate the hash value or last modification time of the metadata configuration file. If the configuration file has not changed, the core can directly read the previously parsed list of processor classes from the build cache, without repeating the IO scan and class loading operations. This optimization significantly improves the execution efficiency of the configuration phase.
[0065] Step S5220: Obtain the class object of the processor class corresponding to the instrumentation processor, so as to register the instrumentation processor in the bytecode processing framework.
[0066] The core framework identifies the type of the processor class obtained through the service loading mechanism. When a processor class is determined to be an instrumented processor type, the core framework executes a lookup strategy to extract only the class object of that processor class and keep it in an uninstantiated state. Subsequently, the core framework uses the extracted class object as a registration parameter to call the underlying instrumentation configuration interface of the Android build tool, thereby completing the registration of the instrumented processor in the build process.
[0067] The core of the framework can iterate through the list of all processor classes obtained and use type checking methods in the reflection mechanism, such as Class.isAssignableFrom(), to analyze the inheritance relationship and interface implementation of the processor classes in order to determine whether they belong to instrumentation processors or general task / traversal processors.
[0068] For classes identified as instrumenters, the framework core can directly retain a reference to the class object. During this process, the framework core controls the invocation of any constructors for that class, ensuring that no runtime instance of the instrumenter is created during the registration phase. This mechanism is called the "lookup strategy," and its purpose is to completely transfer lifecycle management to the host tools.
[0069] The framework core can obtain the build variant component of the current Android application and call the instrumentation transformation API provided by that component, such as `instrumentation.transformClassesWith()`. When calling this method, the framework core passes the extracted class object as the first parameter and configures the appropriate scope, such as `PROJECT` or `ALL`. Through this operation, the framework core successfully mounts the business logic provided by the processor module into the underlying bytecode processing pipeline of the Android build tools.
[0070] Step S5230: Instantiate the processor classes corresponding to the general task processor and the traversal processor to register the general task processor and the traversal processor in the bytecode processing framework.
[0071] The core framework identifies the type of the processor class obtained through the service loading mechanism. When a processor class is determined to be a general task processor or a traversal processor type, the core framework uses reflection to create a runtime instance object of that processor class. Subsequently, the core framework stores the generated instance object in a runtime container maintained internally by the bytecode processing framework, such as in an ordered list or mapping table, thereby establishing the core framework's direct scheduling and lifecycle management rights over the processor.
[0072] An instance object can refer to a concrete, "live" object that has been allocated space in memory and initialized with a state. Unlike instrumentation processors, which only require registering class definitions, general task processors and traversal processors have their methods called by the framework core, such as traverse() and connect(), so instantiation must be completed during the registration phase.
[0073] The core of the framework can traverse the list of processor classes and use the type checking interface in the reflection mechanism to determine the class of the general task / traversal processor.
[0074] For classes identified as general task / traversal handlers, the framework core can further utilize instantiation interfaces in the reflection mechanism, such as Constructor.newInstance(), to create runtime instance objects. After obtaining a runtime instance of the processor class, you can store the processors in an ordered list, such as a List, to iterate through them. <traverseprocessor>This ensures that subsequent scanning and conversion phases can be iteratively called in sequence; for general task processors, a mapping table with task name as the key can be used, for example...<String,TaskProcessor> This allows for on-demand lookup. After registration, the framework core can call the instance's initialization lifecycle methods, such as init(), to notify the processor that it is ready.
[0075] As can be seen from the above embodiments, this application automatically obtains processor classes by employing a service loading mechanism and executes differentiated registration strategies based on the technical characteristics of the processors. For instrumented processors, a lookup strategy is used to obtain class definitions to adapt to the underlying concurrent interfaces of the Android build tools. For general task and traversal processors, instantiation is used to incorporate them into the framework's internal container management. This achieves the technical effect of unifying and ensuring compatibility of heterogeneous bytecode processing modes within the same orchestration system. It effectively solves the problem of a lack of a unified management framework caused by the fragmentation of different instrumentation technologies in existing technologies, and decouples the framework core from specific business implementations.
[0076] Based on any embodiment of the method in this application, the step of reading the bytecode of the target class file set and calling the traversal processor to obtain the global class information of the bytecode during the scanning phase includes: Step S5410: Construct a class reader to read the bytecode of the target class file set.
[0077] For each class file to be processed in the target class file set, the core of the framework instantiates a class reader. Then, the core of the framework configures the parsing mode of the class reader and drives it to read the binary data of the class file, convert it into bytecode in memory, and provide a data source for subsequent information collection.
[0078] A class reader can refer to a component used to parse Java bytecode files (.class). It is responsible for parsing the binary data stream stored on disk into structured data defined by the Java Virtual Machine Specification, such as the constant pool, access flags, class names, interfaces, fields, and methods.
[0079] The core of the framework can first start a concurrent processing mechanism, using a custom worker class to encapsulate each JAR file entry or class directory file in the target class file set into an independent reading task.
[0080] The core of the framework can submit reading tasks to the thread pool using the Worker.submit() method, and the class reader construction logic will be executed in each concurrent thread.
[0081] In each read task, the framework core can read the contents of the target file into memory through a file input stream or a byte array buffer.
[0082] Step S5420: Construct the first visitor chain corresponding to the bytecode of the target class file set, connect the visitors provided by the traversal processor to the first visitor chain, and add a class structure node to the end of the first visitor chain.
[0083] For the bytecode of the target class file set, the framework core initializes a first visitor chain in memory to manage the bytecode event propagation path. Then, the framework core traverses all registered traversal processors, sequentially calling the access interface provided by each processor to connect the visitors generated by each traversal processor to the first visitor chain in order, forming an ordered sequence of processing nodes. Finally, the framework core appends a class structure node to the end of the first visitor chain. This node is used to receive and aggregate the bytecode event stream after propagation through the entire chain, and transform it into a tree structure object in memory.
[0084] The first visitor chain can be a dedicated logical processing link for the scanning phase, based on the chain of responsibility pattern or decorator pattern, allowing multiple processors to process the same bytecode data stream serially. The first chain is used for read-only information acquisition and does not involve bytecode modification.
[0085] Visitors can be bytecode processing units based on the event-driven pattern, such as ClassVisitor in ASM, which contains a series of callback methods, such as visitMethod and visitField.
[0086] When constructing the first visitor chain, a preset interface of the bytecode processor, such as the `createVisitor` or `getVisitor` method, can be called to obtain a visitor instance generated by the bytecode processor. This visitor instance can be injected with the bytecode processor's configuration information, global context information, or stage state information, and then connected to the first visitor chain. Similarly, when constructing the second visitor chain, the same method can be used to obtain the visitor instance of the corresponding bytecode processor and connect it to the corresponding visitor chain.
[0087] A class structure node can be an object that transforms streaming events into a static tree structure, such as the ClassNode in ASM. Placing it at the end of the chain allows you to capture and store the complete structure of the entire class, supporting random access analysis logic.
[0088] The core of the framework can create an instance of the first visitor chain. This object internally maintains pointers to the head and tail of the chain. Initially, both the head and tail of the chain point to an empty placeholder node or directly to the first node to be connected.
[0089] The core of the framework can obtain a list of all registered traversal processors. Through a loop or iterator, it can call the traversal interface of each traversal processor in turn, such as the traverse(chain) method. In the interface call, the traversal processor instantiates its custom class visitor object and calls the connection method provided by the first visitor chain, such as connect(visitor).
[0090] Upon receiving a connection request, the first visitor chain can perform pointer operations, including setting the "next node" pointer of the current tail node to the newly arrived visitor and updating the tail pointer to the new visitor. Through pointer operations, the logic of multiple traversal processors is physically chained together; for example, the bytecode event stream will propagate in the order of "processor A, processor B, ...".
[0091] Once all registered traversal processors have completed the connection, the framework core can instantiate an empty class structure node object, such as new ClassNode().
[0092] The core framework can call append methods of the first visitor chain, such as append(node), to attach the class structure node object to the end of the chain. After being collected in real time by all processors, the bytecode event stream is finally settled in the class structure node, forming a complete memory object tree, which serves as the data source for tree analysis.
[0093] Step S5430: Call the class reader to scan the bytecode of the target class file set to obtain first scan information, and propagate the first scan information along the first visitor chain.
[0094] The core of the framework triggers the execution interface of the built class reader, driving it to parse the bytecode in the target class file set. During the parsing process, the class reader converts the read bytecode structure into standardized first scan information (i.e., bytecode event stream). Subsequently, the core of the framework directs the first scan information to the head node of the first visitor chain, so that it is passed sequentially along the chain structure to each traversal processor and the end class structure node, thereby realizing the unidirectional streaming distribution of bytecode data.
[0095] Chain propagation refers to a data flow mechanism based on the chain of responsibility model. A reader only needs to send an event to the head of the chain, and each bytecode processor on the chain automatically forwards the event to the next bytecode processor after processing it, until the tail of the chain. This ensures that data only needs to be read once to be shared by multiple consumers.
[0096] The class reader parses the underlying bytecode array, reading the magic number, version number, constant pool, access flags, class name, parent class name, and interface list sequentially according to the Java class file format specification. For each structure item parsed, the class reader generates a corresponding callback event. For example, when parsing a class name, it generates a `visit(version, access, name, signature, superName, interfaces)` event; when parsing a method, it generates a `visitMethod(access, name, descriptor, signature, exceptions)` event. This discrete set of events collectively constitutes the first scan information.
[0097] When the framework core calls the class reader, it can apply specific parsing optimization flags. For example, using the "skip debug information" (SKIP_DEBUG) flag instructs the reader to completely ignore debugging attributes such as source filenames, line number tables, and local variable tables during parsing. Using the "skip stack frame calculation" (SKIP_FRAMES) flag instructs the reader to skip the unpacking and verification of stack mapping frames and not calculate the maximum stack depth and maximum number of local variables when parsing method bodies. By applying skip debug information and skipping stack frame calculation, the framework core ensures that the class reader focuses only on parsing critical structures such as class header information, field definitions, and method signatures, thereby minimizing performance overhead during the scanning phase.
[0098] Step S5440: During the propagation process, based on the visitor of the traversal processor, the first scan information is collected in real time as global class information.
[0099] When the first scan information propagates along the first visitor chain, the core of the framework triggers the visitor logic of the traversal processors corresponding to each node on the chain. The visitors of the traversal processors intercept specific bytecode events and extract the metadata required for cross-class analysis from the first scan information at the moment the event flows through, such as class inheritance relationships, interface implementation declarations or annotation markers, and aggregate them into global class information. Subsequently, the traversal processors write the extracted metadata into the global context module or internal cache of the bytecode processing framework in real time and allow the first scan information to continue to propagate downstream.
[0100] Traversal handlers can implement standard visitors, such as ClassVisitor. When the first scan information propagates to the traversal handler, the framework core can automatically call the specific callback method overridden by the traversal handler to capture bytecode events, including the capture class definition, capture annotations, and capture method signatures.
[0101] Step S5450, and / or, during the propagation process, a class structure node tree of the first scan information is generated based on the class structure nodes, and the class structure node tree is passed to the traversal processor to obtain global class information.
[0102] When the first scan information propagates to the end of the first visitor chain, the framework core uses the class structure node located at the end of the chain to aggregate the flowing bytecode events into a class structure node tree in memory. Subsequently, the framework core uses the constructed complete class structure node tree as a parameter to call back or pass it to the registered traversal processor. The traversal processor receives the tree object, performs random access analysis on it, extracts metadata from it, such as the instruction sequence or annotation parameters in the method body, and stores the extracted metadata as global class information in the global context module of the bytecode processing framework.
[0103] When constructing the first visitor chain, the core framework can attach an empty class structure node to the tail of the chain. As the first scan information driven by the class reader flows through each processor on the chain, these events eventually reach the class structure node at the tail of the chain.
[0104] Internally, class structure nodes can implement event listener interfaces, converting received events such as `visitMethod` and `visitField` into corresponding objects, such as `MethodNode` and `FieldNode`, and populating them into their own field or method lists. When the class reader triggers the `visitEnd` event, the current node becomes a complete class structure node tree, containing all the static structure data of the current class.
[0105] After receiving the tree-shaped object, the traversal processor can perform non-linear deep analysis, such as traversing the list of methods to examine the list of instructions within a method; reading annotation nodes on classes or methods to analyze nested annotation parameter values; and when analyzing an inner class, making a joint judgment by holding a reference to the outer class and combining it with information from the global context.
[0106] As can be seen from the above embodiments, this application constructs a class reader and integrates a traversal processor and a first visitor chain of class structure nodes during the scanning phase, drives bytecode to propagate along the chain, and uses a dual-channel mechanism of real-time streaming acquisition of visitors and / or random access analysis of the class structure node tree to obtain global class information. This achieves the technical effect of efficiently establishing complete global class information in a single I / O read process, thereby significantly improving construction performance while supporting global cross-class analysis needs in complex scenarios.
[0107] Based on any embodiment of the method in this application, the step of identifying the class files to be modified in the target class file set according to the global class information during the conversion stage, and calling all registered bytecode processors in a pre-arranged order to sequentially perform bytecode modification operations on the bytecode of the class files to be modified, and outputting the final class file, includes: Step S5510: Construct the second visitor chain corresponding to the bytecode of the class file to be modified, and connect all the visitors provided by the registered bytecode processors to the second visitor chain in a pre-arranged order.
[0108] For each class file identified as to be modified, the core framework initializes an independent second visitor chain in memory to manage bytecode modification logic. Subsequently, the core framework traverses all registered bytecode processors stored in the internal container, including general task processors, instrumentation processors, and traversal processors, following the pre-arranged order established by each processor during the registration phase, such as the order of registration. The core framework sequentially calls the modification interface of each processor, driving it to generate the corresponding bytecode modification visitor, and connects the visitor to the second visitor chain, thereby constructing an ordered processing pipeline dedicated to performing bytecode modification operations.
[0109] The second visitor chain differs from the first visitor chain in the scanning phase. This chain is specifically designed for the transformation phase, carrying not only the flow of data but also its changes. Each node (visitor) on the second visitor chain may intercept, replace, or add bytecode events that flow through it. Constructing a separate second visitor chain is for state isolation, ensuring that temporary states in the scanning phase do not pollute the logic of the modification phase.
[0110] The core of the framework can instantiate a second visitor chain object, which internally maintains pointers to the head and tail of the chain. Initially, the tail of the chain points to a basic write node.
[0111] The core of the framework can recreate a new class structure node to ensure that the second visitor chain is in a pure state.
[0112] The core of the framework can obtain a list of all registered bytecode processors and iterate through each processor in the pre-arranged order of the list.
[0113] Before connecting the bytecode processor to the chain, the framework core can call the processor's intercept interface, such as interceptTransform(fileInfo, globalContext).
[0114] The bytecode processor can determine whether it needs to process the bytecode based on the passed bytecode and global class information, such as whether the current class inherits from BaseActivity. If the bytecode processor returns true (indicating interception / no processing), it skips the bytecode processor based on the interception interface and continues processing the next one in the list. If it returns false (indicating no interception / processing), it executes the next connection operation. This mechanism ensures that the second visitor chain only contains bytecode processors that actually need to modify the current file, avoiding the performance loss caused by running inactive code.
[0115] For bytecode processors that are not intercepted, the framework core calls their transformation interface, such as transform(chain). In the interface implementation, the bytecode processor can instantiate its custom modification visitor and call the chain object's connect method, such as chain.connect(visitor), to perform pointer update operations.
[0116] When performing a pointer update operation, the cv field of the current tail node can be pointed to the newly passed-in modification visitor.
[0117] When performing a pointer update operation, the tail pointer can be updated to point to the new modifier, thus physically linking the bytecode processors together.
[0118] When the bytecode data stream enters the head of the chain, it can flow in the order of "processor 1, processor 2, ..., processor N". Each subsequent processor always operates based on the modification result of the previous processor, thus realizing the orderly superposition of modification logic.
[0119] Step S5520: Call the class reader to scan the bytecode of the target class file to be modified to obtain second scan information, and propagate the second scan information along the second visitor chain.
[0120] For each class file to be modified, the core framework initiates the parsing process of the built class reader, driving it to parse the binary bytecode of the file. During the parsing process, the class reader converts the read bytecode structure into standardized second scan information. Subsequently, the core framework directs the second scan information to the head node of the second visitor chain, so that it is passed to each bytecode processor on the chain in sequence along the chain structure.
[0121] The second scan information differs from the first scan information in the scanning phase; this information is specifically prepared for the conversion phase.
[0122] The core of the framework can instantiate a class reader object for the current class file to be modified, for example, newClassReader(bytes).
[0123] When configuring the class reader, the core framework can apply specific full parsing flags, such as ClassReader.EXPAND_FRAMES. These flags instruct the class reader to expand the compressed StackMapTable into a more manipulable internal format when parsing bytecode.
[0124] The core framework can call the class reader's receive method, such as `accept()`. When calling this method, the core framework can pass the head node of the second visitor chain as a parameter, along with the configured resolution flags.
[0125] The core framework can utilize worker classes to concurrently obtain second-level QR code information. For reading and propagating different class files to be modified, tasks are submitted to a thread pool for concurrent execution. Each thread independently maintains its own class reader and second visitor chain instance, ensuring data isolation and security in a multi-threaded environment.
[0126] Step S5530: During the propagation process, all registered bytecode processors are invoked to sequentially perform bytecode modification operations on the second scan information.
[0127] When the second scan information propagates along the second visitor chain, the core of the framework drives the visitor logic of the bytecode processors corresponding to each node on the chain. Each bytecode processor's visitor intercepts the flowing bytecode events in sequence according to its connection position in the chain, and performs bytecode modification operations on the events according to preset business rules and global class information. Subsequently, each visitor propagates the modified bytecode events to downstream nodes until they are transmitted to the write component at the end of the chain, thereby completing the substantial transformation of the file to be modified.
[0128] Bytecode modification operations refer to actions that alter the sequence of events during the transmission of bytecode event streams, including insertion, replacement, and deletion.
[0129] Step S5540: Convert the modified second scan information into the final class file.
[0130] The framework core receives and aggregates the second scan information after it has been modified by all bytecode processors; then, the framework core reserializes the event stream into binary bytecode data; finally, the framework core writes the generated binary bytecode data to the storage medium to generate the final class file for use in the subsequent build process of the Android build tools.
[0131] When constructing the second visitor chain, the core framework can attach a bytecode writing component, such as the ClassWriter of the ASM framework, to the physical end of the chain.
[0132] When the second scan information is propagated to the bytecode writing component, the component can automatically maintain the bytecode offset, constant pool index, and stack frame mapping. When the event stream ends, the framework core calls the component's exported interface, such as toByteArray(), to obtain the complete binary bytecode data containing the modified logic.
[0133] As can be seen from the above embodiments, this application constructs a second visitor chain during the conversion phase and connects all registered bytecode processors in series into the chain in a pre-arranged order, driving the bytecode data stream of the class file to be modified to propagate along the chain. This allows each processor to execute modification operations sequentially based on global class information, achieving the technical effect of transforming concurrent, multi-source modification logic into linear and ordered pipeline processing. This effectively solves the problems of multi-task collaborative modification conflicts and uncertain results in the prior art, and completes the modification logic of all processors during the serialization process, achieving a high degree of determinism in the construction result and a balance between construction performance and construction efficiency.
[0134] Based on any embodiment of the method in this application, the construction of the first visitor chain or the second visitor chain includes: Step S5411: Construct an empty visitor chain, which maintains a head pointer and a tail pointer to control the propagation path of the first scan information or the second scan information.
[0135] When preparing to execute the scanning or transformation phase, the core of the framework first instantiates a visitor chain object in memory with an initial empty state. The visitor chain object initializes and maintains reference pointers to the head and tail pointers. The core of the framework uses the head pointer to define the entry position of the first or second scan information and the tail pointer to define the insertion position of the bytecode processor, thereby constructing a dynamically expandable and data flow-controlled logical transmission channel.
[0136] The core of the framework can define a class named ClassVisitorChain, which declares two member variables, a head pointer and a tail pointer, namely private ClassVisitor head and private ClassVisitortail.
[0137] If the visitor chain is empty, the framework core can initialize both head and tail as a virtual root node or a passthrough node. This node does not perform any operations; it only serves as the anchor point of the chain, ensuring that calling data transfer methods in an empty chain state will not cause a null pointer exception.
[0138] The core of the framework can be configured with a visitor chain object to expose a data receiving interface, such as accept(ClassReader reader).
[0139] In the implementation of the data receiving interface, the framework core can bind the data output target of the bytecode reading component to an internal head pointer. This setting establishes the starting point of the propagation path. No matter how the chain grows, the external data source only needs to interact with a fixed chain object, and the data will be automatically routed to the first bytecode processor pointed to by the head pointer.
[0140] The core framework can provide a node appending interface in the visitor chain object, such as connect(ClassVisitor visitor).
[0141] The node appending interface can achieve fast insertion with O(1) complexity using the tail pointer. This includes calling the linking method of the node currently pointed to by the tail pointer, such as setNext(visitor), to physically connect the new node to the end of the chain; and updating the tail pointer to point to the newly added visitor node. Through this mechanism, the core of the framework can efficiently control the extension of the propagation path, ensuring that subsequently added processors are always at the end of the path.
[0142] Step S5412: Identify the type and number of bytecode processors that need to be connected to the current visitor chain, connect their visitors to the tail of the current visitor chain in sequence, and update the tail pointer in real time until all bytecode processors are connected to construct the first visitor chain or the second visitor chain.
[0143] The core framework iterates through the registered containers to identify the type and number of bytecode processors that meet the requirements of the current processing stage (scanning or transformation). Then, the core framework initiates a chained assembly process, using the tail pointer of the visitor chain to sequentially call each identified bytecode processor and connect the visitors generated by it to the end node of the current chain. After each connection operation is completed, the core framework updates the tail pointer in real time to ensure that it always points to the most recently connected visitor, until all processors to be executed have been connected, thus completing the construction of the first or second visitor chain.
[0144] As can be seen from the above embodiments, this application constructs and maintains a blank visitor chain with head and tail pointers, and dynamically identifies the type and number of bytecode processors to be connected according to the needs of the processing stage. It uses the tail pointer mechanism to connect the visitors of each processor to the tail of the chain in sequence and updates the pointers in real time to complete the chain construction. This achieves the technical effect of efficiently assembling heterogeneous processors into a linear and ordered execution pipeline, thereby ensuring the determinism of the data propagation path and the controllability of the execution order during bytecode processing. It effectively solves the conflict and instability problems caused by disordered execution when multiple tasks work together in the prior art.
[0145] Based on any embodiment of the method in this application, obtaining a class object of the processor class corresponding to the instrumentation processor to register the instrumentation processor in the bytecode processing framework includes: Step S5221: When registering the instrumentation processor, obtain the configuration object corresponding to the instrumentation processor through reflection.
[0146] During the registration process of the instrumentation processor, the core framework uses reflection to analyze the generic interface definition of the current instrumentation processor class to determine the configuration parameter types declared by the processor. Subsequently, based on the analyzed configuration parameter types, the core framework instantiates the corresponding configuration object in memory.
[0147] The core of the framework can call reflection APIs, such as Class.getGenericInterfaces(), to obtain type information of all interfaces implemented by the current instrumenter class.
[0148] The framework core can iterate through the type information of interfaces to find parameterized types that match the standard instrumentation interface, such as AsmClassVisitorFactory. Once a match is found, the framework core calls the getActualTypeArguments() method to extract the actual generic parameter array declared for that interface. Typically, the first element of this array is the configuration parameter type corresponding to that processor.
[0149] After obtaining the configuration interface type, the framework core can perform instantiation based on the type characteristics of the configuration parameter type. For example, if the type is defined as an interface, the framework core uses a dynamic proxy mechanism or bytecode generation tool to create a proxy object that implements the interface as the configuration object; if the type is defined as a regular class, the framework core uses the reflection API, such as Class.getDeclaredConstructor().newInstance(), to call its parameterless constructor and directly create the configuration object.
[0150] The core of the framework can read user-preset build configuration data, map the build configuration data to the configuration object, and thus generate a configuration object carrying valid runtime parameters.
[0151] Step S5222: Store the configuration object in the global cache with the class name of the instrumentation processor as the key, so that the corresponding configuration object can be retrieved from the global cache according to the class name during the scanning and transformation phases.
[0152] The core framework extracts the unique identifier of the currently registered instrumentation processor class, which is the fully qualified class name of the processor class. Subsequently, the core framework establishes a key-value mapping relationship between the fully qualified class name and the configuration object, and persists this mapping relationship to the global cache maintained by the bytecode processing framework. Through this operation, the core framework builds a configuration data source independent of the Android build tool's lifecycle, enabling instrumentation processors that are subsequently instantiated by the Android build tool during the scanning and transformation phases to directly retrieve and load the corresponding runtime configuration parameters from the global cache through their own class name index.
[0153] Global cache can refer to a thread-safe container that resides at the Java Virtual Machine process level, such as InstrumentConfigCache.
[0154] The core framework can create a thread-safe mapping container based on a hash table, such as ConcurrentHashMap.<String,Object> This container serves as a global cache.
[0155] When registering an instrumentation processor, the framework core can call the getName() or getCanonicalName() method of the current instrumentation processor class to obtain its fully qualified class name string, such as "com.example.plugin.PrivacyProcessor".
[0156] The core framework can use the fully qualified class name as the key and the configuration object as the value to store it in the global cache.
[0157] All instrumented processors on the processor module side can inherit from an abstract base class provided by the framework core, such as AbsBytecodeInstrumenter. This abstract base class encapsulates the logic for retrieving configuration objects, for example, defining the getConfig() method.
[0158] When the build process enters the scanning or transformation phase, the instrumentation processor can perform self-retrieval operations, including calling this.getClass().getName() to get the class name of the current instance; When the build process enters the scanning or transformation phase, the Android build tool instantiates an instrumentation processor using the registered class object. At this time, the instrumentation processor can perform self-retrieval operations, including calling `this.getClass().getName()` to get the class name of the current instance; checking whether the obtained class name contains a suffix automatically generated by the Android build tool or the underlying injection framework, such as `$$Inject`, `_Decorated`, etc. If it exists, the suffix is truncated and removed to restore the original instrumentation processor class name; using the cleaned original class name, the global cache is queried by calling the static access interface provided by the framework core, such as `InstrumentConfigCache.getConfig(className)`. If the cache is hit, the corresponding configuration object is returned; if not, an empty or default configuration is returned.
[0159] Step S5223: Inject the retrieved configuration object into the instrumentation processor to achieve parameter passing.
[0160] The instrumentation processor retrieves the matching configuration object from the global cache based on its fully qualified class name and injects the configuration object into the instrumentation processor. Through this operation, the instrumentation processor achieves runtime parameter binding, so that when executing specific class file editing logic, it can read and apply the user-preset configuration parameters, thus completing reliable parameter passing across the limitations of the host tool.
[0161] As can be seen from the above embodiments, this application utilizes reflection to obtain and instantiate configuration objects during the registration of instrumentation processors, establishes a global caching mechanism with processor class names as keys and configuration objects as values, and enables the instrumentation processor to retrieve and inject configuration objects from the global cache through class name indexing at runtime. This achieves stable and reliable parameter injection, eliminating reliance on potentially unreliable parameter passing mechanisms in the host build tool. This technical effect ensures the normal operation and functional completeness of the heterogeneous instrumentation processor mode within a unified orchestration framework, effectively supporting the stability of unified orchestration and multi-task collaboration for heterogeneous processing modes.
[0162] Based on any embodiment of the method in this application, before performing the scanning phase and the conversion phase on the target class file set sequentially, the following steps are included: Step S4310: Perform multi-level filtering on the target class file set, wherein the multi-level filtering includes filtering class files that do not need to be processed according to preset rules.
[0163] Before the formal scanning phase, the framework core initiates a preprocessing process for the target file set. The framework core loads a predefined multi-level filtering strategy, which includes user-defined rules, framework built-in rules, and file format rules. Subsequently, the framework core traverses each file entry in the target file set and applies the multi-level filtering strategy for matching and verification in turn, thereby accurately dividing the file set into "file subsets that need bytecode processing" and "file subsets that do not need processing" to reduce and optimize the processing scope.
[0164] The framework core can apply a user intent-based filtering layer, reading filtering rules configured by the user in the build script, such as `filterNot` closures or exclusion lists. When traversing the collection of target class files, the framework core can match the package name, class name, or build variant name of the current class file with the filtering rules. For example, if the user configures `filterNot{it.name.startsWith("com.example.test")}`, then all files whose package names begin with `com.example.test` will be marked as requiring no processing.
[0165] The core framework can apply a built-in system-level filtering layer to exclude automatically generated classes in the Android build system. This includes identifying and filtering files that conform to Android resource class naming conventions, such as matching regular expressions like .*R\$.*\.class or .*R\.class; checking file extensions and automatically filtering out files without the .class extension, such as images and text resources, but retaining JAR files for further inspection.
[0166] For JAR files in the target class file set, the framework core can apply a third layer of filtering when reading their entries, including checking the directory structure and metadata files within the JAR package; automatically skipping the signature file, manifest file, and Java module description file under the META-INF / directory; and automatically skipping empty entries that only represent folders.
[0167] Step S4320: Distribute the filtered class files that do not require processing to the incremental compilation path so that they can support native incremental compilation.
[0168] Based on the results of multi-layer filtering, the core framework identifies class files marked as not requiring processing and directs them to the incremental compilation path. In this path, the core framework calls the file appending or incremental change interface provided by the Android build tool to output the class files as a normal class file directory, rather than packaging them into an archive file. Through this operation, the core framework enables the class files to be recognized by the native incremental compilation mechanism of the Android build tool, so that synchronization operations are only performed when the files undergo substantial changes, skipping useless repeated builds.
[0169] An incremental compilation path can refer to a bypass processing channel, such as the toAppend path, in which files are directly synchronized with the file system instead of going through the time-consuming bytecode parsing and writing process.
[0170] The framework core iterates through the target class file collection. For class files marked as not requiring processing, the framework core can call internally defined append processing interfaces, such as the toAppend API. This interface directs the class file to a dedicated file synchronization task, such as AppendTask.
[0171] In the file synchronization task, the core framework can declare support for incremental builds through annotations such as @Incremental, and request the Android build tools to inject a change list object, such as InputChanges.
[0172] The core of the framework can query the change list objects and only retrieve class files whose status is added, modified, or deleted. For class files whose status is not required, no operation is performed.
[0173] Step S4330: Output the class files to be processed as zero-compressed archive files.
[0174] The core framework directs the filtered and marked class files that need to be converted to the full conversion path. After completing the bytecode scanning and modification operations, the core framework aggregates all the modified class file data streams and calls the archive writing component. The core framework is configured to use zero compression mode for the archive writing component, which writes the aggregated class file data into a single archive file for output, in order to eliminate compression calculation overhead and adapt to the decompression requirements of the subsequent build process.
[0175] Zero compression can refer to storing ZIP / JAR files without performing Deflate compression.
[0176] As can be seen from the above embodiments, this application achieves the effect of reducing redundant disk I / O overhead and CPU computing resource waste by performing multi-layer filtering on the target class file set, diverting class files that do not need to be processed to the incremental compilation path, and outputting class files that need to be processed as zero-compressed archive files. This ensures the performance of the build process while taking into account the complex global cross-class analysis requirements and the stability of multi-task collaboration.
[0177] like Figure 2 As shown, a file editing apparatus according to one aspect of this application includes a framework initialization module 5100, a processor registration module 5200, a two-stage scheduling module 5300, a scan execution module 5400, and a conversion execution module 5500. The framework initialization module 5100 initializes a bytecode processing framework in response to a build variant event. The processor registration module 5200 registers multiple types of bytecode processors in the bytecode processing framework according to a pre-arranged order. These multiple types of bytecode processors include a general-purpose task processor, an instrumentation processor, and a traversal processor. The two-stage scheduling module 5300 is used to process the bytecode... The code processing framework obtains a set of target class files and calls the various types of bytecode processors to perform a scanning phase and a conversion phase on the target class file set sequentially. The scanning execution module 5400 is used to read the bytecode of the target class file set during the scanning phase and obtain the global class information of the bytecode by traversing the processors. The conversion execution module 5500 is used to identify the class files to be modified in the target class file set according to the global class information during the conversion phase, and call all registered bytecode processors to perform bytecode modification operations on the bytecode of the class files to be modified in a pre-arranged order, and output the final class file.
[0178] Based on any embodiment of the device in this application, the processor registration module 5200 includes: The processor discovery module is used to obtain the processor class through the service loading mechanism, wherein the processor class corresponds to the bytecode processor; The class object extraction module is used to obtain the class object of the processor class corresponding to the instrumentation processor, so as to register the instrumentation processor in the bytecode processing framework; An instantiation registration module is used to instantiate the processor classes corresponding to the general task processor and the traversal processor, so as to register the general task processor and the traversal processor in the bytecode processing framework.
[0179] Based on any embodiment of the apparatus in this application, the scanning execution module 5400 includes: A bytecode reading module is used to construct a class reader to read the bytecode of the target class file set; The visitor chain construction module is used to construct the first visitor chain corresponding to the bytecode of the target class file set, connect the visitors provided by the traversal processor to the first visitor chain, and add class structure nodes to the end of the first visitor chain. The scanning and propagation module is used to call the class reader to scan the bytecode of the target class file set to obtain first scanning information, and propagate the first scanning information along the first visitor chain; The real-time acquisition module is used to collect the first scan information as global class information in real time based on the visitor of the traversal processor during the propagation process. And / or, a node tree generation module is used to generate a class structure node tree of first scan information based on class structure nodes during the propagation process, and pass the class structure node tree to the traversal processor to obtain global class information.
[0180] Based on any embodiment of the apparatus in this application, the conversion execution module 5500 includes: The visitor chain construction module is used to construct the second visitor chain corresponding to the bytecode of the class file to be modified, and to connect all the visitors provided by the registered bytecode processors to the second visitor chain in a pre-arranged order. The scanning and propagation module is used to call the class reader to scan the bytecode of the target class file to be modified to obtain second scanning information, and propagate the second scanning information along the second visitor chain; The execution module is modified to call all registered bytecode processors during the propagation process and sequentially execute the bytecode modification operation of the second scan information. The class file generation module is used to convert the modified second scan information into the final class file.
[0181] Based on any embodiment of the apparatus in this application, the scanning execution module 5400 or the conversion execution module 5500 includes: The blank chain initialization module is used to construct a blank visitor chain, which maintains a head pointer and a tail pointer to control the propagation path of the first scan information or the second scan information. The visitor chain assembly module is used to identify the type and number of bytecode processors that need to be connected to the current visitor chain, connect their visitors to the tail of the current visitor chain in sequence, and update the tail pointer in real time until all bytecode processors are connected to construct the first visitor chain or the second visitor chain.
[0182] Based on any embodiment of the apparatus in this application, the class object extraction module includes: Configure a reflection acquisition module to acquire the configuration object corresponding to the instrumentation processor through reflection when registering the instrumentation processor; A configuration cache storage module is configured to store the configuration object in a global cache with the class name of the instrumentation processor as the key, so that the corresponding configuration object can be retrieved from the global cache according to the class name during the scanning and transformation phases. The configuration injection module is used to inject the retrieved configuration object into the instrumentation processor to achieve parameter passing.
[0183] Based on any embodiment of the device in this application, prior to the two-stage scheduling module 5300, the following is included: A multi-layer filtering module is used to perform multi-layer filtering on the target class file set, wherein the multi-layer filtering includes filtering class files that do not need to be processed according to preset rules; The incremental splitting module is used to split the filtered, unprocessed class files to the incremental compilation path so that it can support native incremental compilation. The zero-compression archiving module is used to output the class files that need to be processed as zero-compression archive files.
[0184] like Figure 3 As shown in the diagram, another embodiment of this application also provides an electronic device, wherein the internal structure of the electronic device is illustrated. The electronic device includes a processor, a computer-readable storage medium, a memory, and a network interface connected via a system bus. The computer-readable storage medium stores an operating system, a database, and computer-readable instructions. The database may store a sequence of control information. When the computer-readable instructions are executed by the processor, the processor can implement the file editing method described in this application. The processor of the electronic device provides computing and control capabilities to support the operation of the entire electronic device. The memory of the electronic device may store computer-readable instructions. When the computer-readable instructions are executed by the processor, the processor can execute the file editing method described in this application. The network interface of the electronic device is used for communication with a terminal. Those skilled in the art will understand that... Figure 3 The structure shown is merely a block diagram of a portion of the structure related to the present application and does not constitute a limitation on the electronic device to which the present application is applied. The specific electronic device may include more or fewer components than shown in the figure, or combine certain components, or have different component arrangements.
[0185] In this execution method, the processor is used for execution. Figure 2 The system contains the specific functions of each module and its submodules. The memory stores the program code and various data required to execute these modules or submodules. The network interface is used for data transmission between the user terminal and the server. In this execution method, the memory stores the program code and data required to execute all modules / submodules in the file editing device of this application. The server can call the server's program code and data to execute the functions of all submodules.
[0186] This application also provides a storage medium storing computer-readable instructions, which, when executed by one or more processors, cause the one or more processors to perform the steps of the method described in any embodiment of this application.
[0187] Those skilled in the art will understand that all or part of the processes in the methods of the above embodiments of this application can be implemented by a computer program instructing related hardware. This computer program can be stored in a non-volatile readable storage medium, and when executed, it can include the processes of the embodiments of the above methods. The aforementioned storage medium can be a computer-readable storage medium such as a magnetic disk, optical disk, read-only memory (ROM), or random access memory (RAM).
[0188] The above description is only a partial implementation method of this application. It should be noted that for those skilled in the art, several improvements and modifications can be made without departing from the principles of this application, and these improvements and modifications should also be considered within the scope of protection of this application.< / traverseprocessor> < / project>
Claims
1. A file editing method, characterized in that, include: In response to the build variant event, initialize the bytecode processing framework; In the bytecode processing framework, multiple types of bytecode processors are registered in a pre-arranged order, including general-purpose task processors, instrumentation processors, and traversal processors. The target class file set is obtained through the bytecode processing framework, and the various types of bytecode processors are invoked to perform the scanning and conversion phases on the target class file set sequentially. During the scanning phase, the bytecode of the target class file set is read, and the traversal processor is called to obtain the global class information of the bytecode; During the conversion phase, the class files to be modified in the target class file set are identified based on the global class information, and all registered bytecode processors are called in a pre-arranged order to perform bytecode modification operations on the bytecode of the class files to be modified in sequence, and the final class file is output.
2. The file editing method according to claim 1, characterized in that, The bytecode processing framework registers multiple types of bytecode processors in a pre-arranged order. These multiple types of bytecode processors include general-purpose task processors, instrumentation processors, and traversal processors. The processor class is obtained through a service loading mechanism, and the processor class corresponds to a bytecode processor. Obtain the class object of the processor class corresponding to the instrumentation processor, so as to register the instrumentation processor in the bytecode processing framework; Instantiate the processor classes corresponding to the general task processor and the traversal processor to register the general task processor and the traversal processor in the bytecode processing framework.
3. The file editing method according to claim 1, characterized in that, During the scanning phase, the bytecode of the target class file set is read, and the traversal processor is invoked to obtain the global class information of the bytecode, including: Construct a class reader to read the bytecode of the target class file set; Construct a first visitor chain corresponding to the bytecode of the target class file set, connect the visitors provided by the traversal processor to the first visitor chain, and add a class structure node to the end of the first visitor chain. The class reader is invoked to scan the bytecode of the target class file set to obtain first scan information, and the first scan information is propagated along the first visitor chain; During the propagation process, based on the visitor of the traversal processor, the first scan information is collected in real time as global class information; And / or, during the propagation process, a class structure node tree of the first scan information is generated based on the class structure nodes, and the class structure node tree is passed to the traversal processor to obtain global class information.
4. The file editing method according to claim 1, characterized in that, During the conversion phase, the class files to be modified in the target class file set are identified based on the global class information. Then, all registered bytecode processors are called in a pre-arranged order to sequentially perform bytecode modification operations on the bytecode of the class files to be modified, outputting the final class file, including: Construct a second visitor chain corresponding to the bytecode of the class file to be modified, and connect all visitors provided by the registered bytecode processors to the second visitor chain in a pre-arranged order; The class reader is invoked to scan the bytecode of the target class file to be modified to obtain second scan information, and the second scan information is propagated along the second visitor chain. During the propagation process, all registered bytecode processors are invoked by the visitors, and the bytecode modification operations of the second scan information are executed in sequence. The modified second scan information is converted into the final class file.
5. The file editing method according to claim 3 or 4, characterized in that, The construction of the first visitor chain or the second visitor chain includes: Construct an empty visitor chain that maintains a head pointer and a tail pointer to control the propagation path of the first or second scan information; Identify the type and number of bytecode processors that need to be connected to the current visitor chain, connect their visitors to the tail of the current visitor chain in sequence, and update the tail pointer in real time until all bytecode processors are connected to construct the first visitor chain or the second visitor chain.
6. The file editing method according to claim 2, characterized in that, The step of obtaining a class object of the processor class corresponding to the instrumentation processor, in order to register the instrumentation processor in the bytecode processing framework, includes: When registering the instrumentation processor, the configuration object corresponding to the instrumentation processor is obtained through reflection; The configuration object is stored in the global cache with the class name of the instrumentation processor as the key, so that the corresponding configuration object can be retrieved from the global cache according to the class name during the scanning and transformation phases. The retrieved configuration object is injected into the instrumentation processor to achieve parameter passing.
7. The file editing method according to claim 1, characterized in that, Before performing the scanning and conversion phases on the target file set, the process includes: The target class file set is subjected to multi-level filtering, which includes filtering class files that do not need to be processed according to preset rules; The filtered class files that do not require further processing are redirected to the incremental compilation path to enable native incremental compilation. Output the class files that need to be processed as zero-compressed archive files.
8. A document editing device, characterized in that, include: The framework initialization module is used to initialize the bytecode processing framework in response to build variant events; The processor registration module is used to register multiple types of bytecode processors in the bytecode processing framework in a pre-arranged order. The multiple types of bytecode processors include general task processors, instrumentation processors, and traversal processors. A two-stage scheduling module is used to obtain a set of target class files through the bytecode processing framework, and call the various types of bytecode processors to perform a scanning stage and a conversion stage on the set of target class files in sequence; The scanning execution module is used to read the bytecode of the target class file set during the scanning phase and obtain the global class information of the bytecode by traversing the processor. The conversion execution module is used to identify the class files to be modified in the target class file set according to the global class information during the conversion stage, and to call all registered bytecode processors in a pre-arranged order to perform bytecode modification operations on the bytecode of the class files to be modified in sequence, and output the final class file.
9. An electronic device comprising a central processing unit and a memory, characterized in that, The central processing unit is used to invoke and run a computer program stored in the memory to perform the steps of the method as described in any one of claims 1 to 7.
10. A non-volatile storage medium, characterized in that, It stores, in the form of computer-readable instructions, a computer program implemented according to any one of claims 1 to 7, which, when invoked by a computer, executes the steps included in the corresponding method.